okstra 0.93.0 → 0.94.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/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/agents/workers/antigravity-worker.md +2 -2
- package/runtime/agents/workers/claude-worker.md +1 -3
- package/runtime/agents/workers/codex-worker.md +2 -2
- package/runtime/agents/workers/report-writer-worker.md +0 -6
- package/runtime/prompts/lead/okstra-lead-contract.md +2 -2
- package/runtime/prompts/lead/team-contract.md +2 -18
package/package.json
CHANGED
package/runtime/BUILD.json
CHANGED
|
@@ -93,7 +93,7 @@ The wrapper exists because Claude Code's Bash permission matcher rejects simple-
|
|
|
93
93
|
- Do NOT abort the loop on transient `running` status. Only `completed` or the polling cap (initially 30min, optionally extended once to 35min by mtime grace) end it.
|
|
94
94
|
- **No external timeout from Lead.** This polling loop is the SINGLE timeout authority for this dispatch. Lead MUST NOT impose a separate Agent-call timeout that would terminate this subagent before the polling cap is reached (see team-contract "No external timeout on wrapper subagents").
|
|
95
95
|
- Do NOT issue parallel `BashOutput` calls or speculate about progress between polls.
|
|
96
|
-
- **No standalone `sleep` between polls.** The harness blocks `sleep` calls of 5 seconds or longer as a circumvention vector and explicitly forbids chaining shorter sleeps to work around it. `BashOutput` itself is the wait primitive — calling it again immediately after a `running` status is correct.
|
|
96
|
+
- **No standalone `sleep` between polls.** The harness blocks `sleep` calls of 5 seconds or longer as a circumvention vector and explicitly forbids chaining shorter sleeps to work around it. `BashOutput` itself is the wait primitive — calling it again immediately after a `running` status is correct.
|
|
97
97
|
|
|
98
98
|
8. After the polling loop exits with `completed`, perform terminal-status determination BEFORE returning:
|
|
99
99
|
|
|
@@ -101,7 +101,7 @@ The wrapper exists because Claude Code's Bash permission matcher rejects simple-
|
|
|
101
101
|
|
|
102
102
|
b. **CLI failure first.** If the final `BashOutput` reports a non-zero `exit_code`, follow the **CLI failure** rule in §"Error reporting" before returning. Do NOT perform the result-file check on a failed exit — `cli-failure` already covers it.
|
|
103
103
|
|
|
104
|
-
c. **Result-file existence check (exit 0 only).** If `exit_code == 0` BUT no file exists at the extracted Result Path, the Antigravity CLI returned 0 without producing the analysis artifact
|
|
104
|
+
c. **Result-file existence check (exit 0 only).** If `exit_code == 0` BUT no file exists at the extracted Result Path, the Antigravity CLI returned 0 without producing the analysis artifact (it streamed prose, hit its token budget or a sandbox EPERM mid-`Write`, and exited 0 with the artifact never persisted). Forwarding the partial stdout degrades lead synthesis, so this path is required.
|
|
105
105
|
1. Capture the final ~10 lines of the wrapper's live log for diagnostics — single Bash call: `tail -n 10 "${prompt_path%.md}.log"` (substitute the literal absolute prompt-history path; the wrapper writes the log next to it per the §"trace pane" comment in `okstra-antigravity-exec.sh`). Write the captured lines to a temp file (e.g. `<errors-sidecar-dir>/agy-result-missing-tail.txt`) so `--stderr-excerpt-file` can reference it.
|
|
106
106
|
2. Record a `cli-failure` event directly to the run-level error log via the exact `okstra error-log append-observed` template in §"Error reporting" — substitute `--exit-code 0`, `--duration-ms <observed-ms>`, `--message "okstra-antigravity-exec.sh exited 0 but no result file at <abs-path>"`, and `--stderr-excerpt-file <temp-tail-path>`.
|
|
107
107
|
3. Return `ANTIGRAVITY_RESULT_MISSING: agy exited 0 but result file absent at <abs-path>` instead of the raw stdout. The lead is responsible for deciding redispatch per `team-contract` "Lead Redispatch Policy on Result-Missing".
|
|
@@ -51,9 +51,7 @@ Unlike the Codex / Antigravity workers, you are an in-process Claude subagent
|
|
|
51
51
|
|
|
52
52
|
5. **MCP usage**: The canonical list of MCP servers and tools available for this run lives in the lead prompt's `## Available MCP Servers` section (sourced from `.okstra/project.json`'s `mcpServers` array). When the task requires inspection of an external system covered by one of those servers, call the listed tool directly by name (e.g. `mcp__<server>__<tool>`). Do NOT shell out via `claude --mcp-cli call ...` or run the tool name as a Bash command — those are not valid invocation paths. If a server you need is not listed, record `MCP not available for this run` in your worker output rather than guessing a tool name.
|
|
53
53
|
|
|
54
|
-
6.
|
|
55
|
-
|
|
56
|
-
7. When `Task Type` is `improvement-discovery`, the lead's Phase 1.5 reflect-back log at `<RUN_DIR>/state/phase-1.5-grilling.md` is the authoritative scope and lens definition. Read its `Resolved scope` and `Resolved lenses` blocks and do NOT re-interpret the brief's raw `scan-scope` / `priority-lenses` fields. Findings that violate the resolved lens whitelist or scope are rejected by `validators/validate-improvement-report.py`.
|
|
54
|
+
6. When `Task Type` is `improvement-discovery`, the lead's Phase 1.5 reflect-back log at `<RUN_DIR>/state/phase-1.5-grilling.md` is the authoritative scope and lens definition. Read its `Resolved scope` and `Resolved lenses` blocks and do NOT re-interpret the brief's raw `scan-scope` / `priority-lenses` fields. Findings that violate the resolved lens whitelist or scope are rejected by `validators/validate-improvement-report.py`.
|
|
57
55
|
|
|
58
56
|
## Required Reading Before Any Analysis
|
|
59
57
|
|
|
@@ -93,7 +93,7 @@ The wrapper exists because Claude Code's Bash permission matcher rejects simple-
|
|
|
93
93
|
- Do NOT abort the loop on transient `running` status. Only `completed` or the polling cap (initially 30min, optionally extended once to 35min by mtime grace) end it.
|
|
94
94
|
- **No external timeout from Lead.** This polling loop is the SINGLE timeout authority for this dispatch. Lead MUST NOT impose a separate Agent-call timeout that would terminate this subagent before the polling cap is reached (see team-contract "No external timeout on wrapper subagents").
|
|
95
95
|
- Do NOT issue parallel `BashOutput` calls or speculate about progress between polls.
|
|
96
|
-
- **No standalone `sleep` between polls.** The harness blocks `sleep` calls of 5 seconds or longer as a circumvention vector and explicitly forbids chaining shorter sleeps to work around it. `BashOutput` itself is the wait primitive — calling it again immediately after a `running` status is correct.
|
|
96
|
+
- **No standalone `sleep` between polls.** The harness blocks `sleep` calls of 5 seconds or longer as a circumvention vector and explicitly forbids chaining shorter sleeps to work around it. `BashOutput` itself is the wait primitive — calling it again immediately after a `running` status is correct.
|
|
97
97
|
|
|
98
98
|
8. After the polling loop exits with `completed`, perform terminal-status determination BEFORE returning:
|
|
99
99
|
|
|
@@ -101,7 +101,7 @@ The wrapper exists because Claude Code's Bash permission matcher rejects simple-
|
|
|
101
101
|
|
|
102
102
|
b. **CLI failure first.** If the final `BashOutput` reports a non-zero `exit_code`, follow the **CLI failure** rule in §"Error reporting" before returning. Do NOT perform the result-file check on a failed exit — `cli-failure` already covers it.
|
|
103
103
|
|
|
104
|
-
c. **Result-file existence check (exit 0 only).** If `exit_code == 0` BUT no file exists at the extracted Result Path, the Codex CLI returned 0 without producing the analysis artifact
|
|
104
|
+
c. **Result-file existence check (exit 0 only).** If `exit_code == 0` BUT no file exists at the extracted Result Path, the Codex CLI returned 0 without producing the analysis artifact (it streamed prose, hit its token budget or a sandbox EPERM mid-`Write`, and exited 0 with the artifact never persisted). Forwarding the partial stdout degrades lead synthesis, so this path is required.
|
|
105
105
|
1. Capture the final ~10 lines of the wrapper's live log for diagnostics — single Bash call: `tail -n 10 "${prompt_path%.md}.log"` (substitute the literal absolute prompt-history path; the wrapper writes the log next to it per the §"trace pane" comment in `okstra-codex-exec.sh`). Write the captured lines to a temp file (e.g. `<errors-sidecar-dir>/codex-result-missing-tail.txt`) so `--stderr-excerpt-file` can reference it.
|
|
106
106
|
2. Record a `cli-failure` event directly to the run-level error log via the exact `okstra error-log append-observed` template in §"Error reporting" — substitute `--exit-code 0`, `--duration-ms <observed-ms>`, `--message "okstra-codex-exec.sh exited 0 but no result file at <abs-path>"`, and `--stderr-excerpt-file <temp-tail-path>`.
|
|
107
107
|
3. Return `CODEX_RESULT_MISSING: codex exited 0 but result file absent at <abs-path>` instead of the raw stdout. The lead is responsible for deciding redispatch per `team-contract` "Lead Redispatch Policy on Result-Missing".
|
|
@@ -110,12 +110,6 @@ Write the data.json (and the audit sidecar `.md`) with your `Write` tool — tha
|
|
|
110
110
|
data.json written to <abs path>; markdown rendered to <abs path>. Sections populated: <count>.
|
|
111
111
|
```
|
|
112
112
|
|
|
113
|
-
<!-- Worker Result File contract lives above, right after the Authority
|
|
114
|
-
section. The legacy "after Authoring Contract" placement was kept
|
|
115
|
-
for one cycle as a courtesy to readers who learned the old layout;
|
|
116
|
-
remove this marker after v0.32. -->
|
|
117
|
-
|
|
118
|
-
|
|
119
113
|
## Error reporting
|
|
120
114
|
|
|
121
115
|
If any tool call fails (Write of the prompt history file, mkdir, MCP call, Read of an input file), append a `tool-failure` entry to the worker errors sidecar at:
|
|
@@ -233,7 +233,7 @@ If the launch prompt contains `Tmux Worker Dispatch Gate`, Phase 3 is recorded a
|
|
|
233
233
|
|
|
234
234
|
Spawn **analysis workers only** in the same turn (Phase 4 in Teams mode; Phase 5 with `run_in_background: true` and no `team_name` when Teams unavailable). Preserve exact roster, role labels, assigned models from the task bundle.
|
|
235
235
|
|
|
236
|
-
**Agent `name` on dispatch (BLOCKING — token-usage attribution depends on it).** Every analysis-worker `Agent(...)` call MUST set `name: "<workerId>-worker"` — `name: "claude-worker"` / `name: "codex-worker"` / `name: "antigravity-worker"` — exactly as the report-writer dispatch sets `name: "report-writer"` ([report-writer](./report-writer.md)). The Agent harness records this `name` as `agentName` in the subagent session jsonl, and the Phase 7 token collector matches each worker's session by that `agentName` (`okstra_token_usage/collect.py`). A worker dispatched **without** `name` produces a session with no `agentName`; the collector cannot attribute it and records the worker as `source: "unavailable"` even though the session exists and is team-tagged
|
|
236
|
+
**Agent `name` on dispatch (BLOCKING — token-usage attribution depends on it).** Every analysis-worker `Agent(...)` call MUST set `name: "<workerId>-worker"` — `name: "claude-worker"` / `name: "codex-worker"` / `name: "antigravity-worker"` — exactly as the report-writer dispatch sets `name: "report-writer"` ([report-writer](./report-writer.md)). The Agent harness records this `name` as `agentName` in the subagent session jsonl, and the Phase 7 token collector matches each worker's session by that `agentName` (`okstra_token_usage/collect.py`). A worker dispatched **without** `name` produces a session with no `agentName`; the collector cannot attribute it and records the worker as `source: "unavailable"` even though the session exists and is team-tagged. Convergence reverify dispatches keep the prefix (`<workerId>-worker-reverify-r<N>`). For `implementation` and `final-verification` dispatches the `name` carries the **functional role** so the FleetView teammate pill and trace panes name the actual job instead of a generic `worker`: the Executor dispatch sets `name: "<workerId>-executor"` (e.g. `codex-executor`) and every verifier dispatch sets `name: "<workerId>-verifier"` (e.g. `claude-verifier`). These role suffixes still attribute correctly — the collector matches any `agentName` beginning `<workerId>-` (`okstra_token_usage/collect.py` `match_prefixes`). **For every CLI (Codex / Antigravity) dispatch, Lead MUST inject a `**Pane role:**` line into the dispatched prompt body whose value is the Agent `name` with the leading `<cli>-` prefix removed** — the wrapper subagent reads it and passes it as the wrapper's 5th `<role>` argument so the tmux trace pane title reads `<cli>-<role>` (which equals the FleetView teammate name) instead of a generic `<cli>-worker` (see `agents/workers/_cli-wrapper-template.md`). So `name: "codex-worker"` → `**Pane role:** worker`, `name: "codex-worker-reverify-r1"` → `**Pane role:** worker-reverify-r1`, `name: "codex-executor"` → `**Pane role:** executor`, `name: "codex-verifier"` → `**Pane role:** verifier`. The wrapper defaults to `worker` when the line is absent, but always inject it so the pane names the actual job.
|
|
237
237
|
|
|
238
238
|
**Agent `model:` on dispatch (BLOCKING — assignment is otherwise ignored).** The `Claude worker` `Agent(...)` call MUST set `model: "<family token of that role's modelExecutionValue>"` (`fable` / `opus` / `sonnet` / `haiku`), per [team-contract](./team-contract.md) "Model Assignment Rules" #3–#4. The claude-worker definition is `model: inherit`, so omitting this parameter makes the worker silently run on the lead's model instead of its manifest assignment — the assigned-vs-actual deviation. `Codex worker` / `Antigravity worker` are exempt: their CLI model is applied via the wrapper's own `--model` argument, so leave their Agent `model:` at `inherit` (rule #5).
|
|
239
239
|
|
|
@@ -393,7 +393,7 @@ After persistence, reply briefly in the resolved Report Language with: completio
|
|
|
393
393
|
| Letting `convergence.maxRounds` default to 2 for `requirements-discovery` | Resolve effective default to `1` for discovery and record in convergence state artifact |
|
|
394
394
|
| Issuing serial Read calls in Phase 1 | The intake files are independent — issue all Read calls in a single message (parallel) |
|
|
395
395
|
| Flagging the claude-worker dispatch prompt as "incomplete" because it lacks `[Required reading]` / `[Error reporting]` blocks | Intentional asymmetry — see [team-contract](./team-contract.md) "Asymmetry between claude-worker and codex/antigravity-worker prompts" |
|
|
396
|
-
| Waiting silently while the dispatched `claude-worker` Agent call returns nothing for many minutes
|
|
396
|
+
| Waiting silently while the dispatched `claude-worker` Agent call returns nothing for many minutes | The claude-worker MUST append a `- PROGRESS: <stage> <ISO-UTC>` line to its audit sidecar (`runs/<task-type>/worker-results/claude-worker-audit-<task-type>-<seq>.md`) at least every 5 minutes (see `agents/workers/claude-worker.md` "Heartbeat" rule). If the sidecar is absent or its mtime is >5 minutes stale, treat the dispatch as `timeout` and redispatch once with a byte-identical prompt; after a second silent hang, record terminal status `timeout` with the missing-sidecar reason in team-state. The authoritative completion signal is the **result file's appearance**, detected via self-scheduled polling (see [team-contract](./team-contract.md) "Worker-completion detection (self-scheduled polling)") — NOT the Agent-call return, which under `team_name` dispatch is just an immediate `Spawned successfully` ack. The heartbeat sidecar is an auxiliary liveness signal layered on top: a missing sidecar after the result file appears is itself a contract violation per the heartbeat rule |
|
|
397
397
|
| Re-sending confirmed findings (`full-consensus`/`partial-consensus`/`worker-unique`) to a worker in Round 2 | Queue pruning rule — see [convergence](./convergence.md) "Round 1-N: Re-verification Loop (queue-pruned)" |
|
|
398
398
|
| Aggregating a `timeout`/`error` reverify dispatch as `DISAGREE` | Worker failure handling — record as `verification-error` and add to `skippedWorkers[]`. See [convergence](./convergence.md) "Worker failure handling in reverify" |
|
|
399
399
|
| Skipping `--substitute-data` in the Phase 7 collector run | Always pass the flag — see [report-writer](./report-writer.md) "Phase 7 token-usage collector" |
|
|
@@ -103,8 +103,6 @@ Audience-scoped file enumeration (BLOCKING — performance optimization):
|
|
|
103
103
|
|
|
104
104
|
Asymmetry note: `claude-worker` runs in-process and the Agent SDK auto-loads its agent definition; lead's dispatch prompt body for claude-worker can therefore be shorter than for codex/antigravity. The Worker Preamble pointer is still emitted for all three so the contract source is identical regardless of dispatch path.
|
|
105
105
|
|
|
106
|
-
Send byte-identical dispatch prompts to every analysis worker (Claude / Codex / Antigravity), modulo the role label and the wrapper-specific path headers. The prior "role-specific emphasis" guidance is retired — specialization lives in Section 6 of the worker output, not in the dispatch prompt body.
|
|
107
|
-
|
|
108
106
|
## Terminal Statuses
|
|
109
107
|
|
|
110
108
|
Terminal statuses that can be recorded for a worker:
|
|
@@ -331,7 +329,7 @@ empty run-level error logs in production.
|
|
|
331
329
|
|
|
332
330
|
- `cli-failure` events are recorded by the wrapper subagent itself (Codex / Antigravity), but **directly to the run-level error log** via `okstra error-log append-observed --error-type cli-failure ...` — NOT via the sidecar. The sidecar is an in-process tool-failure channel only.
|
|
333
331
|
- **Wrapper invocation arity.** Both `okstra-codex-exec.sh` and `okstra-antigravity-exec.sh` accept four required positional arguments plus an optional fifth `<role>`: `<project-root> <model> <prompt-path> <worktree-path> [<role>]`. The fourth (worktree) argument is **mandatory for implementation phase** and optional otherwise. For codex it becomes `--add-dir <worktree>` (sandbox write access); for antigravity it is appended to `--include-directories`. Omitting it during implementation causes the codex sandbox to reject every Edit/Write targeting the worktree with EPERM. Workers extract the path from the `**Worktree:**` / `EXECUTOR_WORKTREE_PATH` / `cwd for every mutating command:` line in the lead prompt. The optional fifth `<role>` is folded into both the caller (worker) pane title `<cli>-<role>-<pid>` and the sibling trace-pane title `<cli>-<role>-<pid>-tail` (e.g. `codex-executor-93421` ↔ `codex-executor-93421-tail`). `<pid>` is the wrapper's own PID and disambiguates concurrent dispatches of the same role. The role value comes from the dispatch prompt's `**Pane role:**` line: `executor` on an `implementation` Executor dispatch, `verifier` on an `implementation` / `final-verification` verifier dispatch, so the trace pane names the actual job rather than a generic `worker`. When no `**Pane role:**` line is present (analysis phases), pass the literal `worker` (the wrapper also defaults to `worker` if the argument is omitted).
|
|
334
|
-
- **Background dispatch + polling contract (Codex / Antigravity wrappers).** Both wrapper subagents MUST dispatch `okstra-codex-exec.sh` / `okstra-antigravity-exec.sh` via `Bash(run_in_background: true)` and poll with `BashOutput(bash_id)` until the shell reports `status == "completed"`, capped at 30 minutes (1800s) of wall-clock elapsed time. `BashOutput` itself is the wait primitive — call it back-to-back; do NOT insert a standalone `sleep` between polls. The Claude Code harness blocks `sleep` calls of 5 seconds or longer as a circumvention vector and explicitly forbids chaining shorter sleeps inside until-loops to work around the block. Workers that hit the contract bug must NOT self-recover with `until ...; do sleep 2; done` wrappers — that path violates the harness anti-circumvention rule, even though it superficially "works". The
|
|
332
|
+
- **Background dispatch + polling contract (Codex / Antigravity wrappers).** Both wrapper subagents MUST dispatch `okstra-codex-exec.sh` / `okstra-antigravity-exec.sh` via `Bash(run_in_background: true)` and poll with `BashOutput(bash_id)` until the shell reports `status == "completed"`, capped at 30 minutes (1800s) of wall-clock elapsed time. `BashOutput` itself is the wait primitive — call it back-to-back; do NOT insert a standalone `sleep` between polls. The Claude Code harness blocks `sleep` calls of 5 seconds or longer as a circumvention vector and explicitly forbids chaining shorter sleeps inside until-loops to work around the block. Workers that hit the contract bug must NOT self-recover with `until ...; do sleep 2; done` wrappers — that path violates the harness anti-circumvention rule, even though it superficially "works". The current rule applies in **every phase** (analysis runs typically complete in 1–2 `BashOutput` calls, so there is no regression for short jobs). Recording responsibilities:
|
|
335
333
|
- Successful completion: return the wrapper's accumulated stdout from the final `BashOutput`. No log entry.
|
|
336
334
|
- Non-zero `exit_code` reported by `BashOutput`: record a `cli-failure` to the run-level error log with the real `exit_code` and observed `duration-ms`.
|
|
337
335
|
- Polling cap reached: before `KillShell`, perform a one-shot **mtime-grace check** on the wrapper's live log (`<prompt>.log`). If the log was written within the last 90 seconds AND grace has not yet been applied this loop, extend the cap from 1800s → 2100s (one-shot +5min) and continue polling. Otherwise (log stale, OR grace already applied), call `KillShell(shell_id)`, record `cli-failure` with `--exit-code 124 --duration-ms <observed_ms> --message "<wrapper> exceeded polling cap (grace=<applied|not-applied>, last_mtime_age=<n>s)"`, then return the language-specific `*_CLI_TIMEOUT` sentinel. The grace exists to absorb token-budget spikes where the CLI is genuinely still producing output past the 30-minute mark; it is a one-shot soft extension, NOT a loop.
|
|
@@ -371,7 +369,7 @@ Every worker result file under `worker-results/` must begin with a standardized
|
|
|
371
369
|
|
|
372
370
|
Task-type and date are **not** repeated in this human header — they already live in the YAML frontmatter (`taskType`, `date`), which is the copy Obsidian indexes. Restating them here added a third, un-indexed, machine-unparsed copy with no value; the frontmatter is the single source for both. The `Target:` line is optional — include it when the run is scoped to a specific path or module, omit it for whole-project runs; when present, place it between the title and the `Model:` line.
|
|
373
371
|
|
|
374
|
-
|
|
372
|
+
Example (Codex / Report-writer headers are identical modulo the role name and model id):
|
|
375
373
|
|
|
376
374
|
```markdown
|
|
377
375
|
# Claude Worker Analysis — jobs:tasks:8852
|
|
@@ -380,20 +378,6 @@ Examples:
|
|
|
380
378
|
**Model:** Claude worker, opus
|
|
381
379
|
```
|
|
382
380
|
|
|
383
|
-
```markdown
|
|
384
|
-
# Codex Worker Analysis — jobs:tasks:8852
|
|
385
|
-
|
|
386
|
-
**Target:** server/auth.ts
|
|
387
|
-
**Model:** Codex worker, <codex-model-id>
|
|
388
|
-
```
|
|
389
|
-
|
|
390
|
-
```markdown
|
|
391
|
-
# Report Writer Worker Analysis — jobs:tasks:8852
|
|
392
|
-
|
|
393
|
-
**Target:** server/auth.ts
|
|
394
|
-
**Model:** Report writer worker, opus
|
|
395
|
-
```
|
|
396
|
-
|
|
397
381
|
Use the actual model identifier recorded in team-state (never invent a model ID — read it from `resultContract.requiredWorkerRoles[*].modelExecutionValue` or the tool response metadata).
|
|
398
382
|
|
|
399
383
|
The header is followed by the standard worker output contract sections (Findings, Missing Information, etc.).
|