@open-agent-toolkit/cli 0.2.18 → 0.2.20

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.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: oat-phase-implementer
3
- version: 1.0.9
3
+ version: 1.0.10
4
4
  description: Implements one plan phase end-to-end, commits each task separately, self-checks between tasks, and handles bounded review fixes when resumed by oat-project-implement.
5
5
  tools: Read, Write, Edit, Bash, Grep, Glob, Task
6
6
  color: cyan
@@ -105,9 +105,12 @@ replaces every task and phase verification command below.
105
105
 
106
106
  ### 1. Verify Phase Base
107
107
 
108
- Confirm the current worktree is clean and its HEAD equals `phase_base_head` or
109
- is an allowed descendant of `expected_base_sha`. For a plan-declared parallel
110
- group, verify this before any task edit.
108
+ Confirm the current worktree is clean and its HEAD exactly equals
109
+ `phase_base_head`. When `expected_base_sha` is supplied, separately confirm
110
+ that `phase_base_head` equals it or is an explicitly allowed descendant. Never
111
+ use ancestry from `expected_base_sha` as a substitute for the exact
112
+ `phase_base_head` check. For a plan-declared parallel group, verify this before
113
+ any task edit.
111
114
 
112
115
  When smoke containment, ownership registration, expected base, or fixture
113
116
  readiness proves the run invalid, return `INVALID_RUN_ABORT` with the evidence.
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2026-07-11.1",
2
+ "version": "2026-07-25.1",
3
3
  "providers": {
4
4
  "codex": {
5
5
  "economy": {
@@ -102,23 +102,33 @@
102
102
  "economy": {
103
103
  "candidates": [
104
104
  "composer-2.5",
105
- "claude-sonnet-5-high",
106
105
  "gpt-5.6-luna-high",
107
106
  "gpt-5.6-luna-xhigh"
108
107
  ]
109
108
  },
110
109
  "balanced": {
111
- "candidates": ["cursor-grok-4.5-high", "gpt-5.6-terra-high"]
110
+ "candidates": [
111
+ "cursor-grok-4.5-high",
112
+ "gpt-5.6-terra-high",
113
+ "claude-opus-5-thinking-low"
114
+ ]
112
115
  },
113
116
  "high": {
114
- "candidates": ["gpt-5.6-sol-medium", "gpt-5.6-sol-high"]
117
+ "candidates": [
118
+ "gpt-5.6-sol-medium",
119
+ "gpt-5.6-sol-high",
120
+ "claude-opus-5-thinking-medium",
121
+ "claude-opus-5-thinking-high"
122
+ ]
115
123
  },
116
124
  "frontier": {
117
125
  "candidates": [
118
126
  "claude-fable-5-thinking-high",
119
127
  "claude-fable-5-thinking-xhigh",
120
128
  "gpt-5.6-sol-xhigh",
121
- "gpt-5.6-sol-max"
129
+ "gpt-5.6-sol-max",
130
+ "claude-opus-5-thinking-xhigh",
131
+ "claude-opus-5-thinking-max"
122
132
  ]
123
133
  }
124
134
  }
@@ -361,13 +361,18 @@ even when the reusable ladder is user-owned.
361
361
  }
362
362
  ```
363
363
 
364
+ The example above is illustrative rather than a copy of the bundled ladder; its
365
+ tiers are trimmed for readability.
366
+
364
367
  The bundled recommendation covers 13 Codex model/effort combinations: Luna and
365
368
  Terra at `low`, `medium`, `high`, and `xhigh`, plus Sol at those efforts and
366
- `max`. Claude covers `haiku`, `sonnet`, `opus`, and `fable`. Cursor covers 12
367
- verified multi-family flat IDs across Composer, Claude, GPT, and Grok. An
368
- explicit mapping connects each flat ladder ID to a separate bracket-form
369
- frontmatter model; configuration and skills never derive or normalize either
370
- form.
369
+ `max`. Claude covers `haiku`, `sonnet`, `opus`, and `fable`. Cursor covers 16
370
+ candidates across four tiers, drawn from a materialization catalogue of 18
371
+ verified multi-family flat IDs spanning Composer, Claude (Sonnet, Opus, and
372
+ Fable), GPT, and Grok; the two figures differ because some approved mappings
373
+ stay materializable without being recommended. An explicit mapping connects
374
+ each flat ladder ID to a separate bracket-form frontmatter model; configuration
375
+ and skills never derive or normalize either form.
371
376
 
372
377
  The corresponding pinned Codex variant catalogue includes
373
378
  `gpt-5.6-luna-high`, `gpt-5.6-terra-xhigh`, `gpt-5.6-sol-high`, and
@@ -17,3 +17,4 @@ Use this section when you are changing OAT itself rather than consuming it as a
17
17
  - [Commit Conventions](commit-conventions.md) - Traceable commit patterns for project and docs work.
18
18
  - [Hooks and Safety](hooks-and-safety.md) - Safety and mutation contracts for provider-sync behavior.
19
19
  - [Smoke Testing](smoke-testing.md) - Runbook for the live workflow smoke runner: prerequisites, scenarios, evidence reports, and recovery.
20
+ - [Verifying Cursor Pins](verifying-cursor-pins.md) - Runbook for probe-verifying a Cursor model pin before shipping it.
@@ -0,0 +1,282 @@
1
+ ---
2
+ title: Verifying Cursor Pins
3
+ description: 'Runbook for probe-verifying a Cursor model pin before shipping it: evidence channel, hook capture, subjects and controls, interpretation, and cleanup.'
4
+ ---
5
+
6
+ # Verifying Cursor Pins
7
+
8
+ A Cursor model pin maps an OAT ladder model ID to the frontmatter selector that
9
+ materialized role files carry, for example `claude-opus-5-thinking-medium` to
10
+ `claude-opus-5[effort=medium]`. Adding one to
11
+ `packages/cli/src/providers/cursor/codec/catalog.ts` requires evidence that
12
+ Cursor actually resolves that selector to the intended model.
13
+
14
+ This runbook produces that evidence. Run it before adding any mapping.
15
+
16
+ ## Why a probe is required
17
+
18
+ `DR-260718-explicit-cursor-pin-mapping` requires mapping-specific,
19
+ native-launch evidence before a mapping may be marked `approved`. Two things
20
+ that look like evidence are not:
21
+
22
+ - **Structural validation.** That a mapping is well-formed says nothing about
23
+ what Cursor does with it.
24
+ - **Agent self-report.** A subagent asked to name its own model is not a
25
+ reliable witness, and the probe agents in this runbook deliberately do not
26
+ ask.
27
+
28
+ The catalog alone is also insufficient wherever a family carries both a
29
+ thinking and a non-thinking flat ID at the same rung. Opus 5 carries both at
30
+ low, medium, and high, so the bracket selector is genuinely ambiguous there and
31
+ only a probe can resolve it. At rungs where only one variant exists, the
32
+ catalog settles the question without a probe — but you still need the probe to
33
+ prove the effort parameter was honored at all.
34
+
35
+ ## Evidence channel
36
+
37
+ Cursor's agent lifecycle hooks report resolution from Cursor itself. Two
38
+ independent events agree:
39
+
40
+ - `subagentStart.subagent_model` — the model the subagent will use, and the
41
+ authoritative field per Cursor's hooks reference.
42
+ - `preToolUse.model` — observed from inside the subagent's own tool call.
43
+
44
+ Two channels that do **not** work:
45
+
46
+ - **The `cursor-agent` CLI and remote runtime.** Agent lifecycle hooks do not
47
+ fire there. A Task subagent launched from that runtime produces zero hook
48
+ events, and every row records as not-reported. Run probes from the Cursor
49
+ desktop app's Agent Chat.
50
+ - **The subagent card label.** It is built from the requested bracket
51
+ parameters and drops the thinking qualifier, so it cannot distinguish the
52
+ thinking and non-thinking variants — precisely the distinction a probe exists
53
+ to settle.
54
+
55
+ As of Cursor 3.12.30, `model_params` (which would carry an explicit `thinking`
56
+ flag) is empty and `model_id` is absent. Thinking is therefore established by
57
+ the resolved slug itself, which is sound because the non-thinking IDs are
58
+ distinct.
59
+
60
+ ## Prerequisites
61
+
62
+ - Cursor desktop app, with the repository open as a workspace.
63
+ - The live catalog for the families you intend to pin:
64
+
65
+ ```bash
66
+ cursor-agent models
67
+ ```
68
+
69
+ Read the full output rather than truncating it. You need to see whether a
70
+ thinking and a non-thinking ID both exist at each rung, and which rung carries
71
+ the family's unqualified display label.
72
+
73
+ ## Setting up capture
74
+
75
+ Both files are temporary. Delete them when the probe is done.
76
+
77
+ Create `.cursor/hooks/g01-capture.sh`:
78
+
79
+ ```bash
80
+ #!/bin/bash
81
+ # TEMPORARY pin-probe capture hook. Delete after probing.
82
+ set -u
83
+
84
+ OUT_DIR="/tmp/g01-probe"
85
+ OUT="$OUT_DIR/hooks.jsonl"
86
+ mkdir -p "$OUT_DIR" 2>/dev/null || :
87
+
88
+ input=$(cat)
89
+ ts=$(date -u '+%Y-%m-%dT%H:%M:%SZ')
90
+
91
+ printf '{"captured_at":"%s","payload":%s}\n' "$ts" "$input" >>"$OUT" 2>/dev/null || :
92
+
93
+ event=$(printf '%s' "$input" |
94
+ sed -n 's/.*"hook_event_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')
95
+
96
+ # Observe only. Never block, never fail closed.
97
+ case "$event" in
98
+ subagentStop) printf '{}\n' ;;
99
+ *) printf '{"permission":"allow"}\n' ;;
100
+ esac
101
+
102
+ exit 0
103
+ ```
104
+
105
+ Make it executable, then register it in `.cursor/hooks.json` for
106
+ `subagentStart`, `subagentStop`, and `preToolUse`:
107
+
108
+ ```json
109
+ {
110
+ "version": 1,
111
+ "hooks": {
112
+ "subagentStart": [
113
+ { "command": ".cursor/hooks/g01-capture.sh", "timeout": 10 }
114
+ ],
115
+ "subagentStop": [
116
+ { "command": ".cursor/hooks/g01-capture.sh", "timeout": 10 }
117
+ ],
118
+ "preToolUse": [{ "command": ".cursor/hooks/g01-capture.sh", "timeout": 10 }]
119
+ }
120
+ }
121
+ ```
122
+
123
+ The hook must observe only. A capture hook that can block or fail closed can
124
+ change the behavior it is supposed to measure.
125
+
126
+ Restart Cursor or reload the window so the hooks register.
127
+
128
+ ## Writing probe agents
129
+
130
+ One throwaway agent per selector, under `.cursor/agents/`. Keep them trivial:
131
+ the probe is the hook payload, not anything the agent produces.
132
+
133
+ ````markdown
134
+ ---
135
+ # TEMPORARY pin probe - not oat-managed. Delete after probing.
136
+ # Class: subject - expect claude-opus-5-thinking-medium
137
+ name: zz-pin-probe-opus5-medium
138
+ description: Temporary pin probe (subject) for claude-opus-5[effort=medium]. Delete after use.
139
+ model: claude-opus-5[effort=medium]
140
+ ---
141
+
142
+ ## Role
143
+
144
+ You are a throwaway pin probe. Run exactly one command and then stop:
145
+
146
+ ```bash
147
+ echo PIN-PROBE zz-pin-probe-opus5-medium
148
+ ```
149
+
150
+ Then reply with the single word `done`. Do not read files or use any
151
+ other tool.
152
+
153
+ Cursor's hook payload is the evidence for this probe. Your own claim about
154
+ your identity is not evidence and is deliberately not requested.
155
+ ````
156
+
157
+ The `echo` exists to force a tool call, which is what produces the
158
+ corroborating `preToolUse` event.
159
+
160
+ ### Subjects and controls
161
+
162
+ Probe every rung you intend to pin. Then add controls, which are what make the
163
+ subject results interpretable:
164
+
165
+ | Class | Example selector | Proves |
166
+ | ---------------- | ------------------------------ | ---------------------------------------------------------------- |
167
+ | Subject | `claude-opus-5[effort=medium]` | The mapping resolves as intended |
168
+ | Positive control | `claude-sonnet-5[effort=high]` | Reproduces an already-verified mapping |
169
+ | Negative control | `claude-opus-9[effort=high]` | Unknown family — the channel reports resolution, not the request |
170
+ | Negative control | `claude-opus-5[effort=ultra]` | Unknown effort — exposes rung-level fallback |
171
+
172
+ The negative controls carry most of the interpretive weight. Without them you
173
+ cannot distinguish a hook that reports what Cursor actually resolved from one
174
+ that merely echoes what you asked for. A bogus family that comes back as the
175
+ bogus family would invalidate the entire run.
176
+
177
+ ## Running
178
+
179
+ Launch each probe agent from the Cursor desktop app's Agent Chat, as a subagent
180
+ with no model override, so Cursor resolves from the agent's frontmatter. Let
181
+ each finish before starting the next.
182
+
183
+ Then read the resolutions:
184
+
185
+ ```bash
186
+ python3 - <<'PY'
187
+ import json
188
+ for line in open('/tmp/g01-probe/hooks.jsonl'):
189
+ p = json.loads(line).get('payload', {})
190
+ if p.get('hook_event_name') == 'subagentStart':
191
+ print(p.get('subagent_name'), '->', p.get('subagent_model'))
192
+ PY
193
+ ```
194
+
195
+ ## Interpreting results
196
+
197
+ ### Unresolvable components fall back silently
198
+
199
+ Cursor does not reject a malformed pin. It substitutes a default for whichever
200
+ component it cannot resolve, with no error or warning:
201
+
202
+ - An unknown **family** falls back to the account default model. Probing
203
+ `claude-opus-9[effort=high]` resolved to `cursor-grok-4.5-high-fast`.
204
+ - An unknown **effort** falls back to that family's default rung. Probing
205
+ `claude-opus-5[effort=ultra]` resolved to `claude-opus-5-thinking-high`.
206
+
207
+ This makes a typo in a selector more dangerous than a plain downgrade: the pin
208
+ silently tracks whatever Cursor currently designates as the default, so a
209
+ vendor-side change alters capability with no change in this repository.
210
+
211
+ ### The default rung is family-specific
212
+
213
+ Exactly one rung per family carries an unqualified display label in the live
214
+ catalog, and that marks the default. It is not always `high`:
215
+
216
+ | Family | Default rung | Unqualified label | Contrast |
217
+ | -------- | ------------ | ----------------- | ------------------------ |
218
+ | Opus 5 | high | `Opus 5 1M` | `Opus 5 1M Medium` |
219
+ | Opus 4.8 | high | `Opus 4.8 1M` | `Opus 4.8 1M Extra High` |
220
+ | Opus 4.7 | **xhigh** | `Opus 4.7 1M` | `Opus 4.7 1M High` |
221
+
222
+ Opus 4.7 is the disconfirming case for a naive "high is always the default"
223
+ reading.
224
+
225
+ ### A default-rung result proves nothing on its own
226
+
227
+ If the rung you requested happens to be the family default, the observation is
228
+ equally consistent with the effort parameter being honored and with it being
229
+ ignored. That row cannot stand alone.
230
+
231
+ Always probe at least one non-default rung in the same family. A set of
232
+ non-default rungs that each resolve as requested is what demonstrates the
233
+ parameter is genuinely honored; a default-rung row is then sound by inference
234
+ across the set rather than from its own evidence.
235
+
236
+ ## Recording the result
237
+
238
+ Add the mapping with a probe record, which ties it to the evidence that
239
+ approved it:
240
+
241
+ ```ts
242
+ approvedMapping(
243
+ 'claude-opus-5-thinking-medium',
244
+ 'claude-opus-5[effort=medium]',
245
+ 'claude-effort',
246
+ { probeName: 'zz-pin-probe-opus5-medium', verifiedAt: '2026-07-25', evidencePath: '...' },
247
+ ),
248
+ ```
249
+
250
+ The record asserts that `submittedSelector` equals the mapping's
251
+ `frontmatterModel` and `resolvedModel` equals its `ladderModelId`. A mapping
252
+ edited later without re-probing therefore fails its own consistency test rather
253
+ than inheriting an approval that never covered the new selector.
254
+
255
+ Retain the raw payloads alongside the summary. They are the primary evidence;
256
+ the summary is an interpretation of them.
257
+
258
+ ## Cleanup
259
+
260
+ Delete every temporary artifact:
261
+
262
+ - `.cursor/hooks.json` and `.cursor/hooks/g01-capture.sh`
263
+ - all `zz-pin-probe-*` agent files
264
+ - the capture file under `/tmp`
265
+
266
+ Before committing retained payloads, redact machine and identity fields.
267
+ Cursor hook payloads carry `user_email`, `workspace_roots`, and an absolute
268
+ `transcript_path`. None carries probe evidence — resolution is read from
269
+ `subagent_model` — so removing them costs nothing and keeps private data out of
270
+ the repository.
271
+
272
+ Confirm the workspace is clean:
273
+
274
+ ```bash
275
+ oat sync --scope project
276
+ ```
277
+
278
+ ## Related
279
+
280
+ - [Smoke Testing](smoke-testing.md) - Runbook for the live workflow smoke runner.
281
+ - [Dispatch Policy](../workflows/projects/dispatch-ceiling.md) - How pins reach the recommendation and role files.
282
+ - [Provider Sync](../provider-sync/providers.md) - Provider-specific sync behavior.
@@ -64,6 +64,23 @@ existing cells. Planning shows the complete recommendation before asking which
64
64
  scope should own it. If the resulting ladder is still missing or incomplete,
65
65
  planning remains blocked rather than replacing the user's explicit values.
66
66
 
67
+ ### Upgrading to a newer recommendation version
68
+
69
+ Preservation applies to whole cells, which has a consequence worth stating
70
+ plainly: when a new recommendation version adds candidates to a tier you have
71
+ already populated, re-running adoption will not give them to you. The existing
72
+ cell is kept intact rather than merged candidate by candidate. Removals are not
73
+ propagated either.
74
+
75
+ To pick up a new version, compare your
76
+ `workflow.dispatchCeiling.recommendationVersion` against the bundled version,
77
+ then either edit the affected cells by hand or clear them and re-adopt.
78
+
79
+ Version `2026-07-25.1` is a live example: it adds Opus 5 rungs to the Cursor
80
+ `balanced`, `high`, and `frontier` tiers and drops `claude-sonnet-5-high` from
81
+ `economy`. An adopter still on the prior version keeps their existing Cursor
82
+ tiers untouched until they take one of those actions.
83
+
67
84
  Before offering adoption, planning runs `oat config list --json` once and treats
68
85
  its output as the effective boundary across shared, repo-local, user, and
69
86
  bundled-default precedence. A complete effective ladder skips adoption even
@@ -194,10 +211,14 @@ candidate in each tier:
194
211
  `max`.
195
212
  - **Claude:** `haiku`, `sonnet`, `opus`, and `fable` across the ordered named
196
213
  tiers.
197
- - **Cursor:** 12 verified multi-family flat IDs across Composer, Claude, GPT,
198
- and Grok. The explicit materialization catalogue maps each flat ladder ID to
199
- a separate bracket-form frontmatter model; OAT does not derive or normalize
200
- either value.
214
+ - **Cursor:** verified multi-family flat IDs across Composer, Claude (Sonnet,
215
+ Opus, and Fable), GPT, and Grok. Two counts apply and they differ: the
216
+ bundled recommendation carries 16 Cursor candidates across the four tiers,
217
+ while the materialization catalogue carries 18 flat IDs. The extra entries
218
+ are approved mappings deliberately kept out of the recommendation but still
219
+ materializable. The catalogue maps each flat ladder ID to a separate
220
+ bracket-form frontmatter model; OAT does not derive or normalize either
221
+ value.
201
222
 
202
223
  The final candidate in a named tier defines that tier's reviewer ceiling. Lower
203
224
  reviewer selection requires a separate reviewed contract; a normal reviewer
@@ -305,6 +326,11 @@ separate evidence layers:
305
326
  - The materialized definition uses the mapping's explicit bracket-form
306
327
  frontmatter model.
307
328
  - Mapping-specific native-launch evidence authorizes the shipped mapping data.
329
+ An approved mapping may carry a probe record whose `submittedSelector` must
330
+ equal the mapping's `frontmatterModel` and whose `resolvedModel` must equal
331
+ its `ladderModelId`, so editing a mapping without re-probing fails its own
332
+ test rather than inheriting an approval it was never granted. See
333
+ [Verifying Cursor Pins](../../contributing/verifying-cursor-pins.md).
308
334
  - `oat doctor` checks current flat-ID catalogue availability, which can detect
309
335
  drift but cannot prove a definition pin.
310
336
  - The launcher records the selected variant and mapped model with `configured`
@@ -316,6 +342,26 @@ prevent a requested definition pin. Native variant acceptance is therefore not
316
342
  runtime-model verification, and skills must not promote self-report or
317
343
  catalogue presence into observed identity.
318
344
 
345
+ #### Unresolvable selectors also fall back silently
346
+
347
+ Entitlement is not the only trigger. Cursor does not reject a malformed pin
348
+ either; it substitutes a default for whichever selector component it cannot
349
+ resolve, with no error or warning:
350
+
351
+ - An unknown family falls back to the account default model. Probing
352
+ `claude-opus-9[effort=high]` resolved to `cursor-grok-4.5-high-fast`.
353
+ - An unknown effort falls back to that family's default rung. Probing
354
+ `claude-opus-5[effort=ultra]` resolved to `claude-opus-5-thinking-high`.
355
+
356
+ The default rung is family-specific and is not always `high` — Opus 4.7
357
+ defaults to `xhigh`. A typo in a pinned selector therefore ships a
358
+ working-but-wrong model that silently tracks a vendor-controlled default, so
359
+ capability can change with no corresponding change in the repository.
360
+
361
+ OAT does not currently validate effort rungs at sync time; that is tracked as
362
+ `BL-260726-validate-cursor-pin-effort`. Until it lands, the probe runbook is
363
+ the only guard.
364
+
319
365
  ## Phase and Optional-Worker Layers
320
366
 
321
367
  The phase implementer directly implements the phase tasks from one Phase Scope
@@ -1,6 +1,6 @@
1
1
  {
2
- "cli": "0.2.18",
3
- "docs-config": "0.2.18",
4
- "docs-theme": "0.2.18",
5
- "docs-transforms": "0.2.18"
2
+ "cli": "0.2.20",
3
+ "docs-config": "0.2.20",
4
+ "docs-theme": "0.2.20",
5
+ "docs-transforms": "0.2.20"
6
6
  }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: subagent-orchestration
3
- version: 1.0.0
3
+ version: 1.0.1
4
4
  description: Use when delegating work to subagents or choosing a model for a task — routing by task class, selecting provider-specific models and effort, and verifying subagent claims. Covers OpenAI/Codex, Anthropic/Claude, and Cursor.
5
5
  compatibility: Self-contained; no OAT installation required.
6
6
  user-invocable: true