okstra 0.125.0 → 0.125.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/docs/architecture.md +1 -1
- package/docs/cli.md +1 -1
- package/docs/project-structure-overview.md +7 -3
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/bin/okstra-antigravity-exec.sh +10 -0
- package/runtime/bin/okstra-codex-exec.sh +12 -0
- package/runtime/templates/worker-prompt-preamble.md +17 -3
package/docs/architecture.md
CHANGED
|
@@ -298,7 +298,7 @@ The standard `okstra` workflow applies the following team contract consistently
|
|
|
298
298
|
- The main Claude is always the `Claude lead` and operates in synthesis-only mode.
|
|
299
299
|
- The default required worker roles are `Claude worker`, `Codex worker`, and `Report writer worker`. `Antigravity worker` is optional and is included as required only when explicitly named by `--workers` or the profile's `- Workers:` section.
|
|
300
300
|
- `Report writer worker` focuses on report structure and evidence organization, but `Claude lead` remains the final synthesis owner.
|
|
301
|
-
- The default model contract is computed from central defaults. Fallbacks are `Claude lead`=`opus`, `Claude worker`=`opus`, `Codex worker`=`gpt-5.6-sol`, and `Antigravity worker`=`auto` (when opted in).
|
|
301
|
+
- The default model contract is computed from central defaults. Fallbacks are `Claude lead`=`opus`, `Claude worker`=`opus`, `Codex worker`=`gpt-5.6-sol`, `Report writer worker`=`sonnet`, and `Antigravity worker`=`auto` (when opted in). `Report writer worker` no longer inherits the `Claude lead` model — it resolves from its own catalog `ROLE_DEFAULTS` entry because it does not vote in convergence; `--report-writer-model opus` or `OKSTRA_DEFAULT_REPORT_WRITER_MODEL` restores the previous behavior.
|
|
302
302
|
- Because `Antigravity worker` is optional, it is attempted only in runs where it is explicitly included.
|
|
303
303
|
- Before the final judgment, each required role in the current run's worker roster must have either a result or an explicit terminal status (`completed`, `timeout`, `error`, `not-run`).
|
|
304
304
|
- Every attempted worker (`completed`, `timeout`, `error`) must have an assigned worker prompt history file under the current run's `prompts/` directory.
|
package/docs/cli.md
CHANGED
|
@@ -383,7 +383,7 @@ The central-default environment variables are:
|
|
|
383
383
|
Fallback defaults are:
|
|
384
384
|
|
|
385
385
|
- `Claude lead`: `opus`
|
|
386
|
-
- `Report writer worker`: `
|
|
386
|
+
- `Report writer worker`: `sonnet`
|
|
387
387
|
- `Claude worker`: `opus`
|
|
388
388
|
- `Codex worker`: `gpt-5.6-sol`
|
|
389
389
|
- `Antigravity worker`: `auto`
|
|
@@ -54,13 +54,14 @@ okstra/
|
|
|
54
54
|
│ ├── okstra_vendor/ vendored Jinja2 / MarkupSafe + graphify / networkx (okstra-graphify skill)
|
|
55
55
|
│ ├── lib/okstra/ Bash helpers for okstra.sh
|
|
56
56
|
│ └── lib/okstra-ctl/ Bash control-center subcommands
|
|
57
|
-
├── skills/ Claude Code skills (
|
|
57
|
+
├── skills/ Claude Code skills (13); `_fragments/` holds shared marker blocks
|
|
58
58
|
├── agents/ lead SKILL.md + worker agent specs
|
|
59
59
|
├── prompts/ launch template, phase profiles, wizard prompt JSON
|
|
60
60
|
├── schemas/ JSON schema for final-report data.json
|
|
61
61
|
├── templates/ report, setup, PR, project-doc templates/assets
|
|
62
62
|
├── validators/ run / brief / schedule / view validators
|
|
63
63
|
├── tools/build.mjs source → runtime sync
|
|
64
|
+
├── tools/sync-skill-fragments.mjs expand shared fragment blocks into skills/*/SKILL.md
|
|
64
65
|
├── tools/docs_publication/ public-manual publication pipeline (build-time only; not shipped)
|
|
65
66
|
├── config/docs-publication.json publication inventory: every tracked Markdown path + classification
|
|
66
67
|
├── runtime/ generated install payload; do not edit directly
|
|
@@ -220,6 +221,7 @@ Important modules:
|
|
|
220
221
|
| `run.py` | `prepare_task_bundle()` single authority and CLI parser |
|
|
221
222
|
| `implementation_stage.py` | `implementation` single-stage run orchestration — read the Stage Lifecycle Snapshot → pick an available Stage Map entry → provision an isolated stage worktree → publish the selected stage as run context (extracted from `run.py`) |
|
|
222
223
|
| `stage_targets.py` | Stage readiness/verification policy SSOT — from the Stage Lifecycle Snapshot (`consumers.jsonl` ledger + carry sidecar backfill + active registry reservation) it decides which stage is runnable, which commit it branches from, and what final-verification checks. `order_stage_closure` topologically sorts (Kahn) the dependency closure of the wizard's multi-selected stage set to produce the unattended `chain-stages` chaining order |
|
|
224
|
+
| `stage_fix_carry.py` | fix-run carry derivation for a re-run on an `implementation` stage whose latest final-report data.json carries verifier `FAIL` verdicts — collects the previous report path, previous run HEAD, failed verifiers, carried blocking findings, and a routing recommendation, which `run.py` renders into the analysis profile through the `{{FIX_RUN_CONTEXT}}` token. A first run, or a re-run after `PASS`, yields no carry and renders the token empty |
|
|
223
225
|
| `stage_reconcile.py` | best-effort git reconciliation shared by the stage prepare flow (delegates to `git_reconcile.auto_reconcile`; advisory — failures are only reported to stderr, the dependency gate stays authoritative) |
|
|
224
226
|
| `design_surfaces.py` | deterministic detection of an `implementation-planning` stage's design surface — matches the stage's file-path tokens/suffixes/patterns and action wording via `SurfaceRule` to derive which design input the stage needs among domain contract, DB/table schema, external interface, transaction/consistency, transformation mapping, lifecycle, rollout/observability, and manual user test, plus its evidence (`TriggerEvidence`). An unmappable structure raises `DesignSurfaceError` |
|
|
225
227
|
| `design_prep.py` | fingerprint / materialize / resolve backend for design-preparation requests (CLI: `okstra design-prep <list\|show\|write>`) — computes an assessment fingerprint from the approved planning snapshot's `ASSESSMENT_FIELDS`, idempotently writes an Okstra-owned request under `design-prep-requests/`, and resolves the highest-revision append-only user response under `design-prep-inputs/` whose fingerprint matches as the effective response. Keeps the three authorities (report snapshot / Okstra request / user input) separate and never modifies the report or existing revisions. Sidecar I/O is protected by a directory-fd anchor + flock |
|
|
@@ -342,14 +344,16 @@ Optional (v1.0 backward-compatible) top-level keys:
|
|
|
342
344
|
|
|
343
345
|
### 4.10 `skills/`
|
|
344
346
|
|
|
345
|
-
13 user-facing skills (the only skills `okstra install` copies). The list SSOT is `USER_SKILL_NAMES` in `src/lib/skill-catalog.mjs`; the Claude plugin manifest and the installer both derive from it
|
|
347
|
+
13 user-facing skills (the only skills `okstra install` copies). The list SSOT is `USER_SKILL_NAMES` in `src/lib/skill-catalog.mjs`; the Claude plugin manifest and the installer both derive from it.
|
|
348
|
+
|
|
349
|
+
Boilerplate shared by several skills (bash invocation rule, outdated-CLI preflight, python bootstrap note) is kept canonical in `skills/_fragments/*.md` and expanded in place inside each `SKILL.md` between `<!-- BEGIN FRAGMENT: <name> -->` / `<!-- END FRAGMENT: <name> -->` markers by `tools/sync-skill-fragments.mjs` (`--check` fails on drift). Sources stay fully expanded, so `runtime/` and installed copies remain self-contained; the guards are `tests-js/skill-fragments.test.mjs` and `tests/contract/test_prompt_fragment_ownership.py`.
|
|
346
350
|
|
|
347
351
|
| Skill | User-invocable | Role |
|
|
348
352
|
|---|---:|---|
|
|
349
353
|
| `okstra-brief-gen` | yes | Produce task brief from ticket/doc/link/conversation |
|
|
350
354
|
| `okstra-run` | yes | Start/resume okstra task in current Claude Code session |
|
|
351
355
|
| `okstra-memory` | yes | Store/search/archive global conversation memory under `~/.okstra/memory-book` |
|
|
352
|
-
| `okstra-inspect` | yes | Unified read-side — sub-commands `status` (lifecycle + workStatus), `history` (past runs / re-run / resume), `report` (find final-report), `time` (elapsed-time breakdown), `logs` (wrapper log inventory + cleanup), `cost` (task bundle context/read cost) |
|
|
356
|
+
| `okstra-inspect` | yes | Unified read-side — sub-commands `status` (lifecycle + workStatus), `history` (past runs / re-run / resume), `report` (find final-report), `time` (elapsed-time breakdown), `logs` (wrapper log inventory + cleanup), `cost` (task bundle context/read cost), `errors` (error-log aggregation), `error-zip` (anonymized cross-project error bundle), `recap` (cross-run phase recap). `SKILL.md` is a thin core (preflight + dispatch table + shared rules) and each sub-command body lives in `skills/okstra-inspect/facets/<sub-command>.md`, lazily read only after dispatch resolves; the 1:1 match between dispatch rows and facet files is enforced by `tests/contract/test_okstra_inspect_facets.py` |
|
|
353
357
|
| `okstra-rollup` | yes | Cross-task roll-up — aggregate runs/time/errors across a task-group (or whole project) and synthesize a digest from the report files |
|
|
354
358
|
| `okstra-usage` | yes | Read-only project usage snapshot — aggregate recent run coverage, tokens, known cost, CPU, and wall-clock time by task type (default: 30 days) |
|
|
355
359
|
| `okstra-schedule-gen` | yes | Generate task-group schedule |
|
package/package.json
CHANGED
package/runtime/BUILD.json
CHANGED
|
@@ -254,6 +254,16 @@ mkfifo "$stdout_fifo"
|
|
|
254
254
|
tee -a "$log_path" < "$stdout_fifo" &
|
|
255
255
|
stdout_tee_pid=$!
|
|
256
256
|
|
|
257
|
+
# Disable git's fsmonitor for every git command agy runs in this process tree —
|
|
258
|
+
# the main worktree's fsmonitor daemon leaks its IPC socket into task worktrees,
|
|
259
|
+
# so git status/commit here intermittently fail with `fsmonitor_ipc__send_query`
|
|
260
|
+
# errors. GIT_CONFIG_* scopes the override to this process tree without touching
|
|
261
|
+
# the user's repo config. See `okstra-codex-exec.sh` for the full rationale.
|
|
262
|
+
_gc_idx="${GIT_CONFIG_COUNT:-0}"
|
|
263
|
+
export "GIT_CONFIG_KEY_${_gc_idx}=core.fsmonitor"
|
|
264
|
+
export "GIT_CONFIG_VALUE_${_gc_idx}=false"
|
|
265
|
+
export GIT_CONFIG_COUNT="$(( _gc_idx + 1 ))"
|
|
266
|
+
|
|
257
267
|
agy --print "$(cat "$prompt_path")" --model "$model" "${add_dir_args[@]}" \
|
|
258
268
|
--print-timeout "$PRINT_TIMEOUT" --dangerously-skip-permissions \
|
|
259
269
|
2>> "$log_path" \
|
|
@@ -328,6 +328,18 @@ mkfifo "$stdout_fifo"
|
|
|
328
328
|
tee -a "$log_path" < "$stdout_fifo" &
|
|
329
329
|
stdout_tee_pid=$!
|
|
330
330
|
|
|
331
|
+
# Disable git's fsmonitor for every git command codex runs in this process
|
|
332
|
+
# tree. The main worktree's fsmonitor daemon leaks its IPC socket into task
|
|
333
|
+
# worktrees, so git status/commit here intermittently fail with
|
|
334
|
+
# `fsmonitor_ipc__send_query` errors (workers otherwise recover by hand with
|
|
335
|
+
# `git -c core.fsmonitor=false`). Injecting it via GIT_CONFIG_* scopes the
|
|
336
|
+
# override to this process tree without touching the user's repo config, and
|
|
337
|
+
# appends after any GIT_CONFIG_* the caller already set.
|
|
338
|
+
_gc_idx="${GIT_CONFIG_COUNT:-0}"
|
|
339
|
+
export "GIT_CONFIG_KEY_${_gc_idx}=core.fsmonitor"
|
|
340
|
+
export "GIT_CONFIG_VALUE_${_gc_idx}=false"
|
|
341
|
+
export GIT_CONFIG_COUNT="$(( _gc_idx + 1 ))"
|
|
342
|
+
|
|
331
343
|
codex exec -C "$project_root" ${extra_args[@]+"${extra_args[@]}"} --model "$model" --sandbox workspace-write -c approval_policy=never - \
|
|
332
344
|
< "$prompt_path" \
|
|
333
345
|
2>> "$log_path" \
|
|
@@ -43,9 +43,17 @@ Different recipients need different files. Do NOT include `final-report-template
|
|
|
43
43
|
|
|
44
44
|
## Error reporting (all workers)
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
Record a tool call only when its failure **blocked the step you intended** — a test you needed to run did not start, a file you needed to read was missing, a config resolved against the wrong tree, an edit was rejected. When that happens, append a single entry to your worker errors sidecar at the absolute path the lead provided as `**Errors sidecar path:** <abs-path>`.
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
A non-zero exit code is NOT by itself a failure to record. Many tools use non-zero to report a normal, expected result. Do **NOT** record an entry when:
|
|
49
|
+
|
|
50
|
+
- a search/probe tool (`rg`, `grep`, `find`, `ls`, `test`, `git check-ignore`) exits non-zero solely because it found **no matches**, and you proceed unaffected;
|
|
51
|
+
- you probe an **optional / expected-absent** path (`graphify-out/`, `.project-docs/`, `.scratch/`, an optional lint config, a review pack) and it is absent — detecting absence was the point of the probe;
|
|
52
|
+
- output was truncated but you re-ran and read the content end-to-end.
|
|
53
|
+
|
|
54
|
+
The test: if the non-zero exit changed nothing about what you could do next, it is a normal result, not a `tool-failure`. When in doubt about whether a failure blocked you, record it — under-recording a real blocker is worse than one noisy entry. These benign non-zero exits are the single largest source of error-log noise; keeping them out is what makes the log a signal.
|
|
55
|
+
|
|
56
|
+
If the sidecar file does not exist and you have a real entry to record, create it with `{"schemaVersion": 1, "errors": []}` then append.
|
|
49
57
|
|
|
50
58
|
### Entry schema
|
|
51
59
|
|
|
@@ -109,7 +117,13 @@ For the **improvement-discovery phase** specifically, the dispatched prompt MUST
|
|
|
109
117
|
|
|
110
118
|
- `**Phase 1.5 Grilling Log:** <absolute-path>` — the lead's Phase 1.5 reflect-back log (`<RUN_DIR>/state/phase-1.5-grilling.md`, written before dispatch). Its `Resolved scope` / `Resolved lenses` blocks are the authoritative scope and lens definition for this run. Read the file at this absolute path; do NOT re-derive it from `<RUN_DIR>`, and do NOT re-interpret the brief's raw `scan-scope` / `priority-lenses`. The presence of this anchor is itself the signal that this is an improvement-discovery run — no separate task-type detection is required.
|
|
111
119
|
|
|
112
|
-
|
|
120
|
+
### Path anchoring (BLOCKING — the single largest source of worker tool-failures)
|
|
121
|
+
|
|
122
|
+
Every `.okstra/...` path is anchored at `**Project Root:**`, **never** at your cwd. When your run has a worktree (`**Worktree:**` is present), your cwd is that worktree — and the stage/task worktree does **not** contain the project's `.okstra/` directory. So a bare `Read`/`cat .okstra/tasks/...` from cwd resolves inside the worktree and fails "no such file". This is the same trap whether the path came from the prompt, a manifest field, a prior report's citation, or your own reasoning.
|
|
123
|
+
|
|
124
|
+
- Resolve any project-relative path (`.okstra/...`, `<Result Path>`, `<Prompt History Path>`, a prior-report `path:line` citation) against `**Project Root:**`: `<Project Root>/.okstra/...`. Never use the bare relative form.
|
|
125
|
+
- Mutating build/test commands still run from the worktree cwd (`cd <Worktree> && ...`) — but reads of okstra artifacts (`.okstra/**`) always go through `<Project Root>`, even while cwd is the worktree.
|
|
126
|
+
- If a `.okstra/...` read fails "no such file / does not exist in the worktree", do not retry the same relative path — re-anchor it to `<Project Root>` and read the absolute path.
|
|
113
127
|
|
|
114
128
|
---
|
|
115
129
|
|