opensteer 0.7.1 → 0.8.2

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,90 +1,51 @@
1
1
  ---
2
2
  name: opensteer
3
- description: "Browser automation, scraping, structured extraction, and browser-backed API reverse engineering with the Opensteer CLI and SDK. Use when a task needs to open pages, interact with elements, capture network traffic, write request plans, or turn a browser workflow into reusable code."
3
+ description: "Handles Opensteer browser automation, structured DOM extraction, and browser-backed request replay with the Opensteer CLI and SDK. Use when the user mentions Opensteer, browser automation, real Chromium sessions, persistent workspace browser state, descriptor-backed DOM actions or extraction, request plans, recipes, or browser-backed API replay."
4
+ argument-hint: "[goal]"
4
5
  ---
5
6
 
6
7
  # Opensteer
7
8
 
8
- Use this skill when a task needs a real browser workflow, structured extraction, or browser-backed replay.
9
+ If invoked directly, treat `$ARGUMENTS` as the concrete browser or replay goal. First decide whether the task is primarily DOM automation, request capture/replay, or workspace browser administration.
9
10
 
10
- Choose the reference that matches the job:
11
-
12
- - CLI exploration: [references/cli-reference.md](references/cli-reference.md)
13
- - SDK automation: [references/sdk-reference.md](references/sdk-reference.md)
14
- - Request capture and replay: [references/request-workflow.md](references/request-workflow.md)
15
-
16
- ## Default Workflow
17
-
18
- 1. Start with the CLI when you need to explore a site, inspect state, or prove the workflow on a real page.
19
- 2. Re-snapshot after each meaningful page or DOM change before reusing counters.
20
- 3. Add `--description` when you want selector persistence and later replay.
21
- 4. Move to the SDK when the workflow should become reusable code in the repository.
22
- 5. Move to request capture and request plans when the real target is a browser-backed API.
23
-
24
- ## CLI Exploration
25
-
26
- ```bash
27
- opensteer open https://example.com --name my-workflow
28
- opensteer snapshot action --name my-workflow
29
- opensteer click 3 --name my-workflow --description "primary button"
30
- opensteer snapshot extraction --name my-workflow
31
- opensteer extract --name my-workflow \
32
- --description "page summary" \
33
- --schema '{"title":{"selector":"title"},"url":{"source":"current_url"}}'
34
- opensteer close --name my-workflow
35
- ```
11
+ Use this skill when a task needs a real browser workflow, persistent workspace browser state, structured DOM extraction, or browser-backed request replay.
36
12
 
37
- Rules:
38
-
39
- - Use `opensteer open` once to create the session, then use `goto`, actions, snapshots, and extraction against the same `--name`.
40
- - Treat counter targets as snapshot-local. Always take a fresh `snapshot action` before reusing counters after the page changes.
41
- - Use `snapshot extraction` plus `extract` for structured data. Do not treat snapshot HTML as the final data source.
42
- - Use `--description` whenever the action or extraction should be replayable later.
43
-
44
- ## SDK Automation
45
-
46
- ```ts
47
- import { Opensteer } from "opensteer";
48
-
49
- const opensteer = new Opensteer({
50
- name: "my-workflow",
51
- rootDir: process.cwd(),
52
- browser: { headless: true },
53
- });
13
+ Choose the reference that matches the job:
54
14
 
55
- try {
56
- await opensteer.open("https://example.com");
57
- await opensteer.snapshot("action");
15
+ - CLI exploration and browser admin: [references/cli-reference.md](references/cli-reference.md)
16
+ - SDK automation and reusable code: [references/sdk-reference.md](references/sdk-reference.md)
17
+ - Request capture, plans, and recipes: [references/request-workflow.md](references/request-workflow.md)
58
18
 
59
- const data = await opensteer.extract({
60
- description: "page summary",
61
- schema: {
62
- title: { selector: "title" },
63
- url: { source: "current_url" },
64
- },
65
- });
19
+ ## Startup Checks
66
20
 
67
- console.log(data);
68
- } finally {
69
- await opensteer.close();
70
- }
71
- ```
21
+ - Verify `opensteer` is available in the repo or on `PATH` before planning the workflow.
22
+ - If Chromium binaries are missing, install them through Playwright before debugging page behavior.
23
+ - Reuse an existing workspace id for the same site or feature when one already exists.
72
24
 
73
- Rules:
25
+ ## Mental Model
74
26
 
75
- - Wrap owned sessions in `try/finally` and call `close()`.
76
- - Use `Opensteer.attach(...)` plus `disconnect()` when you are attaching to an existing CLI-owned session.
77
- - Prefer Opensteer methods over raw Playwright calls so actions, extraction, and replay semantics stay inside the product surface.
78
- - Use `networkTag` on actions when you intend to inspect or promote the network traffic they trigger.
27
+ - `workspace` / `--workspace` is the durable unit of state. Persistent workspaces live under `.opensteer/workspaces/<id>`.
28
+ - A workspace stores the browser profile, live browser metadata, artifacts, traces, saved network, DOM descriptors, extraction descriptors, request plans, recipes, auth recipes, and reverse-analysis records.
29
+ - In the SDK, omitting `workspace` creates a temporary root. In the CLI, stateful commands currently require `--workspace <id>`.
30
+ - With a workspace, browser mode defaults to `persistent`. `temporary` creates an isolated browser for the current run. `attach` connects to an already-running Chromium browser.
31
+ - `opensteer browser ...` manages the workspace browser itself. `opensteer close` stops the active session/browser without deleting the workspace. `browser reset` clears cloned browser state. `browser delete` removes workspace browser files.
32
+ - The short CLI only has special parsing for a few common commands. For advanced semantic operations or fields like `persistAsDescription`, use `opensteer run <semantic-operation> --workspace <id> --input-json <json>`.
33
+ - Prefer Opensteer surfaces over raw Playwright so descriptors, extraction payloads, saved network, request plans, recipes, traces, and artifacts stay in the workspace.
79
34
 
80
- ## Request Capture And Replay
35
+ ## Workflow Selection
81
36
 
82
- Use Opensteer's reverse-engineering flow when the deliverable is a custom API or a replayable request plan:
37
+ - Choose the DOM workflow when the answer must come from the rendered page or a real browser interaction.
38
+ - Choose the request workflow when the durable artifact is an HTTP path, request plan, recipe, or reverse-analysis package.
39
+ - Many tasks use both: prove the browser flow first, then capture and promote the underlying request path.
83
40
 
84
- 1. Perform the browser action that triggers the request.
85
- 2. Inspect traffic with `queryNetwork()` or `opensteer network query`.
86
- 3. Retry the request with `rawRequest()` or `opensteer request raw`.
87
- 4. Promote the captured request with `inferRequestPlan()` or `opensteer plan infer`.
88
- 5. Replay it with `request()` or `opensteer request execute`.
41
+ ## Shared Rules
89
42
 
90
- Read [references/request-workflow.md](references/request-workflow.md) before implementing request-plan work.
43
+ - Use `snapshot("action")` or `snapshot action` before counter-based `element` targets.
44
+ - Re-snapshot after navigation or DOM-changing actions before reusing element counters.
45
+ - In the SDK, `selector + description` or `element + description` persists a DOM action descriptor. `description` alone reuses it later.
46
+ - In the CLI, the short `click` / `hover` / `input` / `scroll` forms accept exactly one target. Use `opensteer run dom.* --input-json` when you need `persistAsDescription`.
47
+ - For extraction, `description + schema` authors or updates a persisted extraction descriptor. `description` alone replays the stored extraction payload.
48
+ - Extraction schemas are explicit JSON objects and arrays. Each leaf must be `{ element: N }`, `{ selector: "..." }`, optional `attribute`, or `{ source: "current_url" }`.
49
+ - Persisted extraction replay is deterministic and snapshot-backed. Do not replace `extract()` with `evaluate()` or custom DOM parsing when the desired output fits the extraction schema.
50
+ - Use recipes for deterministic setup work. Use auth recipes for auth refresh/setup specifically. They live in separate registries.
51
+ - Do not reach for removed surfaces such as `--name`, `Opensteer.attach()`, cloud/profile-sync helpers, `local-profile`, legacy snapshot browser modes, or `@opensteer/engine-abp`.
@@ -1,115 +1,133 @@
1
1
  # Opensteer CLI Reference
2
2
 
3
- Use the CLI when you need a fast, stateful loop against a live browser session.
3
+ Use the CLI when you need a fast JSON-first loop against a repo-local workspace browser.
4
4
 
5
- ## Session Loop
5
+ ## Sections
6
+
7
+ - [Quickstart](#quickstart)
8
+ - [Browser Lifecycle And Profile Cloning](#browser-lifecycle-and-profile-cloning)
9
+ - [Browser Modes](#browser-modes)
10
+ - [Advanced Semantic Operations](#advanced-semantic-operations)
11
+ - [Extraction Schema Examples](#extraction-schema-examples)
12
+
13
+ ## Quickstart
6
14
 
7
15
  ```bash
8
- opensteer open https://example.com --name demo
9
- opensteer snapshot action --name demo
10
- opensteer click 3 --name demo --description "primary button"
11
- opensteer input 7 "search term" --name demo --press-enter --description "search input"
12
- opensteer snapshot extraction --name demo
13
- opensteer extract --name demo \
16
+ opensteer browser status --workspace demo
17
+ opensteer open https://example.com --workspace demo
18
+ opensteer snapshot action --workspace demo
19
+ opensteer click --workspace demo --element 3
20
+ opensteer input --workspace demo --selector "input[type=search]" --text "search term" --press-enter true
21
+ opensteer snapshot extraction --workspace demo
22
+ opensteer extract --workspace demo \
14
23
  --description "page summary" \
15
- --schema '{"title":{"selector":"title"},"url":{"source":"current_url"}}'
16
- opensteer close --name demo
24
+ --schema-json '{"title":{"selector":"title"},"url":{"source":"current_url"}}'
25
+ opensteer extract --workspace demo --description "page summary"
26
+ opensteer close --workspace demo
17
27
  ```
18
28
 
19
- ## Core Rules
20
-
21
- - Keep `--name` stable for the whole workflow.
22
- - Use `snapshot action` before counter-based interactions.
23
- - Re-snapshot after any navigation or DOM-changing action before reusing counters.
24
- - Use `--description` when the interaction or extraction should become replayable later.
25
- - CLI commands return JSON for machine-readable actions and data commands.
29
+ - Stateful CLI commands currently require `--workspace <id>`.
30
+ - With a workspace, browser mode defaults to `persistent`.
31
+ - Use `snapshot action` before `--element <n>` targets.
32
+ - `extract --description --schema-json ...` writes or updates a persisted extraction descriptor.
33
+ - `extract --description ...` replays the stored extraction payload with no schema.
26
34
 
27
- ## Navigation And Data
35
+ ## Browser Lifecycle And Profile Cloning
28
36
 
29
37
  ```bash
30
- opensteer goto https://example.com/products --name demo
31
- opensteer snapshot action --name demo
32
- opensteer snapshot extraction --name demo
33
- opensteer extract --name demo --schema '{"items":[{"title":{"selector":"h2"}}]}'
38
+ opensteer browser clone --workspace github-sync \
39
+ --source-user-data-dir "$HOME/Library/Application Support/Google/Chrome" \
40
+ --source-profile-directory Default
41
+ opensteer open https://github.com --workspace github-sync
42
+ opensteer browser status --workspace github-sync
43
+ opensteer close --workspace github-sync
44
+ opensteer browser reset --workspace github-sync
45
+ opensteer browser delete --workspace github-sync
34
46
  ```
35
47
 
36
- ## Browser Connection Modes
37
-
38
- Open a brand-new browser:
48
+ - `browser clone`, `browser reset`, and `browser delete` require a persistent workspace browser.
49
+ - `browser clone` copies a local Chromium profile into `.opensteer/workspaces/<id>/browser/user-data`.
50
+ - `close` stops the active session/browser but keeps the workspace registry, traces, artifacts, and cloned browser data.
39
51
 
40
- ```bash
41
- opensteer open https://example.com --name demo --headless true
42
- ```
52
+ ## Browser Modes
43
53
 
44
- Attach to a live Chromium instance:
54
+ - `persistent`: default with `--workspace`. Browser state lives in the workspace.
55
+ - `temporary`: isolated browser state for the current run.
56
+ - `attach`: connect to a running Chromium browser.
45
57
 
46
58
  ```bash
47
- opensteer open https://example.com --name demo --browser attach-live --attach-endpoint 9222
59
+ opensteer open https://example.com --workspace demo --browser temporary
48
60
  opensteer browser discover
49
- opensteer browser inspect --endpoint 9222
61
+ opensteer browser inspect --attach-endpoint ws://127.0.0.1:9222/devtools/browser/abc
62
+ opensteer open https://example.com --workspace demo --browser attach --attach-endpoint ws://127.0.0.1:9222/devtools/browser/abc
50
63
  ```
51
64
 
52
- Launch from a copied local profile:
65
+ Common options:
53
66
 
54
- ```bash
55
- opensteer open https://example.com --name demo --browser snapshot-session \
56
- --source-user-data-dir "~/Library/Application Support/Google/Chrome" \
57
- --source-profile-directory Default
58
- ```
67
+ - `--headless true|false`
68
+ - `--executable-path <path>`
69
+ - `--arg <value>` repeatable
70
+ - `--timeout-ms <ms>`
71
+ - `--context-json <json>`
72
+ - `--fresh-tab true|false` for `--browser attach`
59
73
 
60
- Launch from a copied authenticated profile:
74
+ ## Advanced Semantic Operations
75
+
76
+ The short CLI only special-cases a small set of commands. For advanced operations and fields not exposed by shorthand parsing, use:
61
77
 
62
78
  ```bash
63
- opensteer open https://example.com --name demo --browser snapshot-authenticated \
64
- --source-user-data-dir "~/Library/Application Support/Google/Chrome" \
65
- --source-profile-directory "Profile 1"
79
+ opensteer run <semantic-operation> --workspace <id> --input-json <json>
66
80
  ```
67
81
 
68
- ## Local Browser Profile Helpers
82
+ Examples:
69
83
 
70
84
  ```bash
71
- opensteer local-profile list
72
- opensteer local-profile inspect --user-data-dir "~/Library/Application Support/Opensteer Chrome"
73
- opensteer local-profile unlock --user-data-dir "~/Library/Application Support/Opensteer Chrome"
74
- ```
85
+ opensteer run dom.click --workspace demo \
86
+ --input-json '{"target":{"kind":"selector","selector":"button.primary"},"persistAsDescription":"primary button","networkTag":"load-products"}'
75
87
 
76
- ## Cloud Profile Cookie Sync
88
+ opensteer run page.goto --workspace demo \
89
+ --input-json '{"url":"https://example.com/products","networkTag":"page-load"}'
77
90
 
78
- ```bash
79
- opensteer profile sync \
80
- --profile-id bp_123 \
81
- --attach-endpoint 9222 \
82
- --domain github.com
91
+ opensteer run network.query --workspace demo \
92
+ --input-json '{"tag":"load-products","includeBodies":true,"limit":20}'
93
+
94
+ opensteer run request-plan.infer --workspace demo \
95
+ --input-json '{"recordId":"rec_123","key":"products.search","version":"v1"}'
96
+
97
+ opensteer run request.execute --workspace demo \
98
+ --input-json '{"key":"products.search","query":{"q":"laptop"}}'
83
99
  ```
84
100
 
85
- ## Network Capture
101
+ - Command aliases such as `network query` and `request-plan infer` still exist, but they usually depend on `--input-json` for nontrivial inputs.
102
+ - Use `run page.goto` when you need `networkTag` on navigation. The short `goto` form only parses the URL positional.
103
+ - Use `run dom.click` / `run dom.input` / `run dom.hover` / `run dom.scroll` when you need `persistAsDescription`.
86
104
 
87
- Inspect the traffic triggered by a session:
105
+ ## Extraction Schema Examples
88
106
 
89
107
  ```bash
90
- opensteer network query --name demo --include-bodies --limit 20
91
- opensteer network save --name demo --tag login-flow
92
- opensteer network diff --name demo --left rec_a --right rec_b
93
- opensteer network probe --name demo --record-id rec_123
94
- opensteer network minimize --name demo --record-id rec_123 --transport context-http
108
+ opensteer snapshot extraction --workspace demo
95
109
  ```
96
110
 
97
- ## Request Plans
98
-
99
- Infer a plan from a captured record, then execute it:
111
+ Explicit field bindings:
100
112
 
101
113
  ```bash
102
- opensteer plan infer --name demo --record-id rec_123 --key products.search --version v1
103
- opensteer plan get --name demo products.search
104
- opensteer request execute --name demo products.search --query q=laptop
105
- opensteer request raw --name demo https://example.com/api/search --transport context-http
114
+ opensteer extract --workspace demo \
115
+ --description "page summary" \
116
+ --schema-json '{"title":{"element":3},"price":{"element":7}}'
117
+
118
+ opensteer extract --workspace demo \
119
+ --description "links" \
120
+ --schema-json '{"url":{"selector":"a.primary","attribute":"href"},"pageUrl":{"source":"current_url"}}'
106
121
  ```
107
122
 
108
- ## Execution Modes
123
+ Arrays with representative rows:
109
124
 
110
- - `managed`: Opensteer launches and owns a fresh browser.
111
- - `attach-live`: Opensteer attaches to an already running Chromium browser.
112
- - `snapshot-session`: Opensteer copies an existing profile into an isolated owned session.
113
- - `snapshot-authenticated`: Opensteer copies a profile while preserving harder authenticated state.
125
+ ```bash
126
+ opensteer extract --workspace demo \
127
+ --description "items" \
128
+ --schema-json '{"items":[{"title":{"selector":"#products li:nth-child(1) .title"},"price":{"selector":"#products li:nth-child(1) .price"}},{"title":{"selector":"#products li:nth-child(2) .title"},"price":{"selector":"#products li:nth-child(2) .price"}}]}'
129
+ ```
114
130
 
115
- Use `--engine abp` on `open` only when the optional `@opensteer/engine-abp` package is installed.
131
+ - Build the exact JSON object you want. The extractor does not accept semantic placeholders like `"string"` or prompt-style schemas.
132
+ - Use `element` fields only with counters from a fresh snapshot in the same live session.
133
+ - For arrays, include one or more representative objects. Add multiple examples when repeated rows have structural variants.
@@ -2,6 +2,30 @@
2
2
 
3
3
  Use this workflow when the deliverable is a custom API, a replayable request plan, or a lower-overhead path than full browser automation.
4
4
 
5
+ ## Sections
6
+
7
+ - [Standard Loop](#standard-loop)
8
+ - [Transport Selection](#transport-selection)
9
+ - [SDK Flow](#sdk-flow)
10
+ - [CLI Equivalents](#cli-equivalents)
11
+ - [Transport Probing](#transport-probing)
12
+ - [Auth Token Acquisition](#auth-token-acquisition)
13
+ - [Input Formats](#input-formats)
14
+ - [Practical Guidance](#practical-guidance)
15
+
16
+ ## Standard Loop
17
+
18
+ 1. Trigger the real browser action that causes the request inside a stable workspace.
19
+ 2. Tag the important navigation or interactions with `networkTag`.
20
+ 3. Inspect the captured traffic and isolate the relevant records.
21
+ 4. Save useful captures to the workspace if they need to survive later analysis.
22
+ 5. Prove the request with `rawRequest()`.
23
+ 6. Promote the winning record into a request plan.
24
+ 7. Add recipes or auth recipes if replay needs deterministic setup.
25
+ 8. Replay the plan from code.
26
+
27
+ This workflow should carry equal weight with DOM automation. Use it whenever the browser page is only the launcher for the real target request.
28
+
5
29
  ## Transport Selection
6
30
 
7
31
  - `direct-http`: the request is replayable without a browser.
@@ -13,11 +37,17 @@ When in doubt, start with browser-backed capture first. Opensteer treats browser
13
37
 
14
38
  ## SDK Flow
15
39
 
16
- 1. Trigger the request from a real page.
40
+ 1. Start a workspace-backed browser flow and tag navigation.
17
41
 
18
42
  ```ts
19
- await opensteer.open("https://example.com/app");
43
+ await opensteer.open();
44
+ await opensteer.goto({
45
+ url: "https://example.com/app",
46
+ networkTag: "page-load",
47
+ });
48
+
20
49
  await opensteer.click({
50
+ selector: "button.load-products",
21
51
  description: "load products",
22
52
  networkTag: "products-load",
23
53
  });
@@ -56,7 +86,15 @@ await opensteer.inferRequestPlan({
56
86
  });
57
87
  ```
58
88
 
59
- 5. Replay the plan from code.
89
+ 5. Save the captured traffic if you want it in the workspace registry.
90
+
91
+ ```ts
92
+ await opensteer.saveNetwork({
93
+ tag: "products-load",
94
+ });
95
+ ```
96
+
97
+ 6. Replay the plan from code.
60
98
 
61
99
  ```ts
62
100
  const result = await opensteer.request("products.search", {
@@ -64,18 +102,116 @@ const result = await opensteer.request("products.search", {
64
102
  });
65
103
  ```
66
104
 
105
+ 7. Add a recipe or auth recipe if replay needs deterministic setup.
106
+
107
+ ```ts
108
+ await opensteer.runRecipe({
109
+ key: "products.setup",
110
+ });
111
+
112
+ await opensteer.runAuthRecipe({
113
+ key: "products.auth",
114
+ });
115
+ ```
116
+
67
117
  ## CLI Equivalents
68
118
 
69
119
  ```bash
70
- opensteer network query --name demo --tag products-load --include-bodies --limit 20
71
- opensteer request raw --name demo https://example.com/api/products --transport context-http
72
- opensteer plan infer --name demo --record-id rec_123 --key products.search --version v1
73
- opensteer request execute --name demo products.search --query q=laptop
120
+ opensteer open --workspace demo
121
+ opensteer run page.goto --workspace demo \
122
+ --input-json '{"url":"https://example.com/app","networkTag":"page-load"}'
123
+ opensteer run dom.click --workspace demo \
124
+ --input-json '{"target":{"kind":"selector","selector":"button.load-products"},"persistAsDescription":"load products","networkTag":"products-load"}'
125
+ opensteer run network.query --workspace demo \
126
+ --input-json '{"tag":"products-load","includeBodies":true,"limit":20}'
127
+ opensteer run request.raw --workspace demo \
128
+ --input-json '{"transport":"context-http","url":"https://example.com/api/products","method":"POST","body":{"json":{"page":1}}}'
129
+ opensteer run request-plan.infer --workspace demo \
130
+ --input-json '{"recordId":"rec_123","key":"products.search","version":"v1"}'
131
+ opensteer run request.execute --workspace demo \
132
+ --input-json '{"key":"products.search","query":{"q":"laptop"}}'
133
+ ```
134
+
135
+ ## Transport Probing
136
+
137
+ Test each discovered API with multiple transports to determine portability:
138
+
139
+ ```ts
140
+ const direct = await opensteer.rawRequest({
141
+ transport: "direct-http",
142
+ url: discoveredUrl,
143
+ method: "GET",
144
+ });
145
+
146
+ const context = await opensteer.rawRequest({
147
+ transport: "context-http",
148
+ url: discoveredUrl,
149
+ method: "GET",
150
+ });
74
151
  ```
75
152
 
153
+ If `direct-http` returns 200, the API is portable and does not need a browser for future calls. If only `context-http` works, the API depends on browser session state.
154
+
155
+ ## Auth Token Acquisition
156
+
157
+ When you discover an auth endpoint, acquire a token and use it to probe for data APIs that may be behind auth:
158
+
159
+ ```ts
160
+ const tokenResp = await opensteer.rawRequest({
161
+ transport: "direct-http",
162
+ url: "https://example.com/api/oauth/token?scope=guest",
163
+ method: "POST",
164
+ });
165
+
166
+ let parsed = tokenResp.data;
167
+ if (parsed === undefined) {
168
+ const body = tokenResp.response.body;
169
+ if (!body) {
170
+ throw new Error("Token response had no body");
171
+ }
172
+ parsed = JSON.parse(Buffer.from(body.data, "base64").toString("utf8"));
173
+ }
174
+
175
+ const token = String((parsed as { access_token: unknown }).access_token);
176
+
177
+ const authed = await opensteer.rawRequest({
178
+ transport: "direct-http",
179
+ url: "https://example.com/api/products",
180
+ method: "GET",
181
+ headers: [{ name: "Authorization", value: `Bearer ${token}` }],
182
+ });
183
+ ```
184
+
185
+ ## Input Formats
186
+
187
+ `rawRequest` expects specific shapes:
188
+
189
+ - `headers`: array of `[{ name, value }]`, not `{ key: value }`.
190
+ - `body`: one of `{ json: { ... } }`, `{ text: "..." }`, or `{ base64: "..." }`. Not raw strings.
191
+ - `request.execute` semantic input includes `key` inside the JSON object. The SDK convenience wrapper `opensteer.request(key, input)` adds that for you.
192
+
76
193
  ## Practical Guidance
77
194
 
195
+ Mandatory steps:
196
+
197
+ - MUST use `goto({ url, networkTag })` to tag navigation. `networkTag` is NOT supported on `open()`. In the CLI, this means `opensteer run page.goto --input-json ...`.
198
+ - MUST query by tag first (`queryNetwork({ tag })`), then query all traffic to catch async requests.
199
+ - MUST probe every discovered first-party API with transport tests. Do NOT just log URLs.
200
+ - MUST call `saveNetwork({ tag })` before closing the session.
201
+ - Use `queryNetwork({ source: "saved" })` when you want to read previously persisted captures after the live session is gone.
202
+
203
+ Common mistakes:
204
+
205
+ - Do NOT pass headers as `{key: value}`. MUST use `[{name, value}]` arrays.
206
+ - Do NOT pass body as a raw string. MUST wrap it in `{json: {...}}`, `{text: "..."}`, or `{base64: "..."}`.
207
+ - Do NOT skip auth probing. If you find an OAuth endpoint, get a token and re-probe with it.
208
+ - Do NOT treat "no data API found" as failure. It is a valid reverse-engineering conclusion that justifies DOM fallback.
209
+ - Do NOT mix up recipes and auth recipes. They are separate registries and can reuse the same key/version independently.
210
+
211
+ Additional guidance:
212
+
78
213
  - Capture the browser action first if authentication, cookies, or minted tokens may matter.
79
- - Save or tag the useful traffic before minimizing or diffing it.
80
214
  - Prefer `direct-http` only after proving the request no longer depends on live browser state.
81
- - Use recipes when the request plan needs deterministic auth refresh or setup work.
215
+ - `inferRequestPlan()` throws if the key+version already exists. Catch the error or bump the version.
216
+ - Use recipes when the request plan needs deterministic setup work. Use auth recipes when the setup is specifically auth refresh or login state.
217
+ - Stay in the DOM workflow only when the rendered page itself is the deliverable. Move here when the request is the durable artifact.