libretto 0.6.12 → 0.6.14

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.
Files changed (82) hide show
  1. package/README.md +3 -8
  2. package/README.template.md +3 -8
  3. package/dist/cli/cli.js +0 -23
  4. package/dist/cli/commands/auth.js +24 -33
  5. package/dist/cli/commands/billing.js +3 -5
  6. package/dist/cli/commands/browser.js +4 -13
  7. package/dist/cli/commands/deploy.js +54 -45
  8. package/dist/cli/commands/execution.js +6 -3
  9. package/dist/cli/commands/experiments.js +1 -1
  10. package/dist/cli/commands/setup.js +2 -295
  11. package/dist/cli/commands/shared.js +1 -1
  12. package/dist/cli/commands/snapshot.js +10 -100
  13. package/dist/cli/commands/status.js +2 -42
  14. package/dist/cli/core/auth-fetch.js +11 -6
  15. package/dist/cli/core/browser.js +13 -8
  16. package/dist/cli/core/config.js +3 -6
  17. package/dist/cli/core/daemon/daemon.js +88 -74
  18. package/dist/cli/core/daemon/exec-repl.js +133 -0
  19. package/dist/cli/core/daemon/exec.js +6 -21
  20. package/dist/cli/core/daemon/ipc.js +47 -4
  21. package/dist/cli/core/daemon/ipc.spec.js +21 -0
  22. package/dist/cli/core/daemon/snapshot.js +2 -29
  23. package/dist/cli/core/exec-compiler.js +8 -3
  24. package/dist/cli/core/experiments.js +1 -28
  25. package/dist/cli/core/providers/index.js +13 -4
  26. package/dist/cli/core/providers/libretto-cloud.js +178 -26
  27. package/dist/cli/index.js +0 -2
  28. package/dist/cli/router.js +9 -6
  29. package/dist/shared/instrumentation/instrument.js +4 -4
  30. package/dist/shared/ipc/socket-transport.d.ts +2 -1
  31. package/dist/shared/ipc/socket-transport.js +16 -5
  32. package/dist/shared/ipc/socket-transport.spec.js +5 -0
  33. package/docs/releasing.md +8 -6
  34. package/package.json +3 -2
  35. package/skills/libretto/SKILL.md +49 -47
  36. package/skills/libretto/references/code-generation-rules.md +6 -0
  37. package/skills/libretto/references/configuration-file-reference.md +14 -12
  38. package/skills/libretto/references/pages-and-page-targeting.md +1 -1
  39. package/skills/libretto/references/site-security-review.md +6 -6
  40. package/skills/libretto-readonly/SKILL.md +2 -9
  41. package/src/cli/cli.ts +0 -24
  42. package/src/cli/commands/auth.ts +24 -33
  43. package/src/cli/commands/billing.ts +3 -5
  44. package/src/cli/commands/browser.ts +6 -16
  45. package/src/cli/commands/deploy.ts +55 -49
  46. package/src/cli/commands/execution.ts +6 -3
  47. package/src/cli/commands/experiments.ts +1 -1
  48. package/src/cli/commands/setup.ts +2 -381
  49. package/src/cli/commands/shared.ts +1 -1
  50. package/src/cli/commands/snapshot.ts +9 -137
  51. package/src/cli/commands/status.ts +2 -50
  52. package/src/cli/core/auth-fetch.ts +9 -4
  53. package/src/cli/core/browser.ts +15 -8
  54. package/src/cli/core/config.ts +3 -6
  55. package/src/cli/core/daemon/daemon.ts +106 -76
  56. package/src/cli/core/daemon/exec-repl.ts +189 -0
  57. package/src/cli/core/daemon/exec.ts +8 -43
  58. package/src/cli/core/daemon/ipc.spec.ts +27 -0
  59. package/src/cli/core/daemon/ipc.ts +81 -23
  60. package/src/cli/core/daemon/snapshot.ts +1 -43
  61. package/src/cli/core/exec-compiler.ts +8 -3
  62. package/src/cli/core/experiments.ts +9 -38
  63. package/src/cli/core/providers/index.ts +17 -4
  64. package/src/cli/core/providers/libretto-cloud.ts +224 -36
  65. package/src/cli/core/resolve-model.ts +5 -0
  66. package/src/cli/core/workflow-runtime.ts +1 -0
  67. package/src/cli/index.ts +0 -1
  68. package/src/cli/router.ts +9 -6
  69. package/src/shared/instrumentation/instrument.ts +4 -4
  70. package/src/shared/ipc/socket-transport.spec.ts +6 -0
  71. package/src/shared/ipc/socket-transport.ts +20 -5
  72. package/dist/cli/commands/ai.js +0 -110
  73. package/dist/cli/core/ai-model.js +0 -195
  74. package/dist/cli/core/api-snapshot-analyzer.js +0 -86
  75. package/dist/cli/core/snapshot-analyzer.js +0 -667
  76. package/dist/cli/framework/simple-cli.js +0 -880
  77. package/scripts/summarize-evals.mjs +0 -135
  78. package/src/cli/commands/ai.ts +0 -144
  79. package/src/cli/core/ai-model.ts +0 -301
  80. package/src/cli/core/api-snapshot-analyzer.ts +0 -110
  81. package/src/cli/core/snapshot-analyzer.ts +0 -856
  82. package/src/cli/framework/simple-cli.ts +0 -1459
@@ -4,7 +4,7 @@ description: "Browser automation CLI for building, maintaining, and running brow
4
4
  license: MIT
5
5
  metadata:
6
6
  author: saffron-health
7
- version: "0.6.12"
7
+ version: "0.6.14"
8
8
  ---
9
9
 
10
10
  ## How Libretto Works
@@ -19,25 +19,29 @@ The npm package includes `src/` (full TypeScript source) and `docs/` for deeper
19
19
 
20
20
  Full documentation is published at [libretto.sh](https://libretto.sh). Available pages:
21
21
 
22
- - Get started: [introduction](https://libretto.sh/get-started/introduction), [installation](https://libretto.sh/get-started/installation), [configuration](https://libretto.sh/get-started/configuration)
23
- - Fundamentals: [core concepts](https://libretto.sh/fundamentals/core-concepts), [how workflow generation works](https://libretto.sh/fundamentals/how-workflow-generation-works), [automation and bot detection](https://libretto.sh/fundamentals/automation-and-bot-detection), [website authentication](https://libretto.sh/fundamentals/website-authentication)
24
- - Workflow guides: [one-shot generation](https://libretto.sh/workflow-guides/one-shot-workflow-generation), [interactive building](https://libretto.sh/workflow-guides/interactive-workflow-building), [debugging workflows](https://libretto.sh/workflow-guides/debugging-workflows), [convert to network requests](https://libretto.sh/workflow-guides/convert-to-network-requests)
25
- - CLI reference: [open and connect](https://libretto.sh/cli-reference/open-and-connect), [sessions](https://libretto.sh/cli-reference/sessions), [profiles](https://libretto.sh/cli-reference/profiles), [snapshot](https://libretto.sh/cli-reference/snapshot), [exec](https://libretto.sh/cli-reference/exec), [run and resume](https://libretto.sh/cli-reference/run-and-resume), [session logs](https://libretto.sh/cli-reference/session-logs), [pages](https://libretto.sh/cli-reference/pages)
26
- - Library API: [workflow](https://libretto.sh/library-api/workflow), [AI extraction](https://libretto.sh/library-api/ai-extraction), [network requests](https://libretto.sh/library-api/network-requests), [file downloads](https://libretto.sh/library-api/file-downloads)
27
- - Hosting: [introduction](https://libretto.sh/hosting/introduction), [GCP](https://libretto.sh/hosting/gcp), [AWS](https://libretto.sh/hosting/aws)
22
+ - Get started: [quickstart](https://libretto.sh/docs/get-started/quickstart), [first workflow](https://libretto.sh/docs/get-started/first-workflow), [deploying](https://libretto.sh/docs/get-started/deploying)
23
+ - Fundamentals: [core concepts](https://libretto.sh/docs/understand-libretto/core-concepts), [how workflow generation works](https://libretto.sh/docs/understand-libretto/how-workflow-generation-works), [automation and bot detection](https://libretto.sh/docs/understand-libretto/automation-and-bot-detection), [website authentication](https://libretto.sh/docs/understand-libretto/website-authentication)
24
+ - Workflow guides: [one-shot generation](https://libretto.sh/docs/guides/one-shot-workflow-generation), [interactive building](https://libretto.sh/docs/guides/interactive-workflow-building), [debugging workflows](https://libretto.sh/docs/guides/debugging-workflows), [convert to network requests](https://libretto.sh/docs/guides/convert-to-network-requests)
25
+ - CLI reference: [open and connect](https://libretto.sh/docs/reference/cli/open-and-connect), [sessions](https://libretto.sh/docs/reference/cli/sessions), [profiles](https://libretto.sh/docs/reference/cli/profiles), [snapshot](https://libretto.sh/docs/reference/cli/snapshot), [exec](https://libretto.sh/docs/reference/cli/exec), [run and resume](https://libretto.sh/docs/reference/cli/run-and-resume), [session logs](https://libretto.sh/docs/reference/cli/session-logs), [pages](https://libretto.sh/docs/reference/cli/pages)
26
+ - Library API: [workflow](https://libretto.sh/docs/reference/runtime/workflow), [AI extraction](https://libretto.sh/docs/reference/runtime/ai-extraction), [network requests](https://libretto.sh/docs/reference/runtime/network-requests), [file downloads](https://libretto.sh/docs/reference/runtime/file-downloads)
27
+ - Libretto Cloud Hosting: [overview](https://libretto.sh/docs/libretto-cloud-hosting/overview), [authentication](https://libretto.sh/docs/libretto-cloud-hosting/authentication), [deployments](https://libretto.sh/docs/libretto-cloud-hosting/deployments)
28
+ - Alternative providers: [overview](https://libretto.sh/docs/alternative-providers/overview), [Kernel](https://libretto.sh/docs/alternative-providers/kernel), [Browserbase](https://libretto.sh/docs/alternative-providers/browserbase), [GCP](https://libretto.sh/docs/alternative-providers/gcp), [AWS](https://libretto.sh/docs/alternative-providers/aws)
28
29
 
29
30
  ## Default Integration Approach
30
31
 
31
- - Prefer network requests first for new integrations unless the user explicitly asks for Playwright or UI automation, then do not use the site's internal API.
32
- - Read `references/site-security-review.md` before committing to a network-first approach on a new site.
33
- - Fall back to passive interception or Playwright-driven UI automation when the security review rules network requests out, the request path is not workable, or the user explicitly asks for Playwright.
32
+ - Use Playwright for navigation and other non-fetch browser behavior, including document and asset loads.
33
+ - Prefer browser-context `fetch()` for data extraction and form submission when the target is a real site fetch/XHR endpoint and `references/site-security-review.md` says the path is safe and workable.
34
+ - Use passive interception when the UI already triggers useful fetch/XHR requests or active fetch is risky.
35
+ - Fall back to Playwright UI automation when fetch is ruled out, the request path is not workable, or the user explicitly asks for Playwright/UI automation.
34
36
 
35
37
  ## Setup
36
38
 
37
- - Use `npx libretto setup` for first-time workspace onboarding. It installs Chromium, syncs skills, and pins the default snapshot model to `.libretto/config.json` when provider credentials are available.
38
- - Re-running `setup` on a healthy workspace shows the current configuration. If credentials are missing for a configured provider, it offers an interactive repair flow.
39
- - Use `npx libretto status` to inspect AI configuration health and open sessions without triggering setup.
40
- - Use `npx libretto ai configure openai|anthropic|gemini|vertex` to explicitly change the snapshot model or provider (advanced override).
39
+ - Use `npx libretto setup` for first-time workspace onboarding. It installs Chromium and syncs skills.
40
+ - Use `npx libretto status` to inspect open sessions without triggering setup.
41
+
42
+ ## Experiments
43
+
44
+ - Use `npx libretto experiments` to list internal feature flags and `npx libretto experiments describe <name>` for usage notes when an experiment is enabled.
41
45
 
42
46
  ## Working Rules
43
47
 
@@ -46,8 +50,8 @@ Full documentation is published at [libretto.sh](https://libretto.sh). Available
46
50
  - Do not treat visibility as interactivity. If an element will not act, inspect blockers before retrying.
47
51
  - Defer repo/code review until you begin generating code, unless the user explicitly asks for it earlier.
48
52
  - Read and follow guidelines in `references/code-generation-rules.md` before generating or editing production workflow code.
49
- - Validation requires a successful clean `run --headless` with confirmation of the actual returned output, not just process success. If the user wants to watch the finished workflow, do a final headed `run` after headless validation succeeds.
50
- - After validation, always show the user: (1) the output/results from the headless validation run, and (2) a headed version of the same command so they can re-run it themselves and watch the browser (e.g. replace `--headless` with `--headed`). Include any `--params` or `--auth-profile` flags the workflow needs.
53
+ - Validation requires a successful clean `run` with confirmation of the actual returned output, not just process success. Use the same headed or headless mode that the workflow run is already using.
54
+ - After validation, always show the user: (1) the output/results from the validation run, and (2) the same command so they can re-run it themselves. Include any `--params`, `--headed`, `--headless`, or `--auth-profile` flags the workflow needs.
51
55
  - Treat exploration sessions as disposable unless the user explicitly wants one kept open.
52
56
  - Get explicit user confirmation before mutating actions or replaying network requests that may have side effects.
53
57
  - Never run multiple `exec` commands at the same time.
@@ -95,20 +99,15 @@ npx libretto session-mode --session my-session
95
99
  ### `snapshot`
96
100
 
97
101
  - Use `snapshot` as the primary page observation tool.
98
- - Always provide both `--objective` and `--context`.
99
- - A single snapshot objective can include multiple questions or analysis tasks.
102
+ - Run `snapshot` without `--objective` or `--context`; the command prints a screenshot path and compact accessibility tree for the current page.
103
+ - Run `snapshot <ref>` to inspect a subtree from the latest full snapshot. Use ref forms printed in the tree, such as `l16`; numeric-suffix aliases such as `e16` also match `l16`.
104
+ - Run an unscoped snapshot before using refs. Subtree snapshots capture a fresh screenshot but reuse the latest cached tree.
100
105
  - Use it before guessing at selectors, after workflow failures, and whenever the visible page state is unclear.
101
- - When analysis is involved, expect it to take time. Use a timeout of at least 2 minutes for shell-wrapped calls.
102
106
 
103
107
  ```bash
104
- npx libretto snapshot \
105
- --objective "Find the sign-in form and submit button" \
106
- --context "I just opened the login page and need the email field, password field, and submit button."
107
- npx libretto snapshot \
108
- --session debug-example \
109
- --page <page-id> \
110
- --objective "Explain why the table is empty" \
111
- --context "I opened the referrals page, applied filters, and expected rows to appear."
108
+ npx libretto snapshot --session debug-example
109
+ npx libretto snapshot <ref> --session debug-example
110
+ npx libretto snapshot --session debug-example --page <page-id>
112
111
  ```
113
112
 
114
113
  ### `exec`
@@ -116,16 +115,18 @@ npx libretto snapshot \
116
115
  - Use `exec` for focused inspection and short-lived interaction experiments.
117
116
  - Use `exec` to validate selectors, inspect data, or prototype a step before you encode it in the workflow file.
118
117
  - Use `exec -` to run multi-line scripts from stdin, especially when the code is too long or complex for a command line argument.
119
- - Available globals: `page`, `context`, `browser`, `state`, `fetch`, `Buffer`.
118
+ - The `exec` REPL is persistent for each browser session. Define helper functions once and reuse them in later `exec` calls.
119
+ - Available globals: `page`, `frame`, `context`, `browser`, `fetch`, `Buffer`.
120
120
  - Let failures throw. Do not hide `exec` failures with `try/catch` or `.catch()`.
121
121
  - Do not run multiple `exec` commands in parallel.
122
122
  - Do not use `exec` in read-only diagnosis flows. Use `readonly-exec` from the `libretto-readonly` skill for those sessions.
123
+ - After successful mutations, `exec` prints page-change diffs from compact snapshots.
123
124
 
124
125
  ```bash
125
- npx libretto exec "return await page.url()"
126
- npx libretto exec "return await page.locator('button').count()"
126
+ npx libretto exec "await page.url()"
127
127
  npx libretto exec "await page.locator('button:has-text(\"Continue\")').click()"
128
- echo "return await page.url()" | npx libretto exec - --session debug-example
128
+ echo "async function textOf(selector) { return await page.locator(selector).textContent(); }" | npx libretto exec - --session debug-example
129
+ npx libretto exec --session debug-example "await textOf('h1')"
129
130
  ```
130
131
 
131
132
  ### `pages`
@@ -135,13 +136,13 @@ echo "return await page.url()" | npx libretto exec - --session debug-example
135
136
 
136
137
  ```bash
137
138
  npx libretto pages --session debug-example
138
- npx libretto exec --session debug-example --page <page-id> "return await page.url()"
139
+ npx libretto exec --session debug-example --page <page-id> "await page.url()"
139
140
  ```
140
141
 
141
142
  ### `run`
142
143
 
143
- - Use `run` to verify a workflow file after creating it or editing it, preferring `run --headless` for the normal fix/verify loop.
144
- - Plain `run` defaults to headed mode.
144
+ - Use `run` to verify a workflow file after creating it or editing it. Use the same headed or headless mode for validation that the workflow run is already using.
145
+ - Plain `run` defaults to headed mode. Do not use `--headless` unless the user asks for headless mode or the existing workflow run already uses it.
145
146
  - Successful runs close the browser by default. Pass `--stay-open-on-success` when you need to inspect the completed state with `pages`, `snapshot`, or `exec`.
146
147
  - Pass `--read-only` if the preserved session should come back locked for follow-up terminal inspection after the workflow run.
147
148
  - If the workflow fails, Libretto keeps the browser open. Inspect the failed state with `snapshot` and `exec` before editing code.
@@ -150,9 +151,9 @@ npx libretto exec --session debug-example --page <page-id> "return await page.ur
150
151
  - Re-run the same workflow after each fix to verify the browser behavior end to end.
151
152
 
152
153
  ```bash
153
- npx libretto run ./integration.ts --headless --params '{"status":"open"}'
154
- npx libretto run ./integration.ts --headless --read-only
155
- npx libretto run ./integration.ts --headless --stay-open-on-success
154
+ npx libretto run ./integration.ts --params '{"status":"open"}'
155
+ npx libretto run ./integration.ts --read-only
156
+ npx libretto run ./integration.ts --stay-open-on-success
156
157
  npx libretto run ./integration.ts --auth-profile app.example.com
157
158
  ```
158
159
 
@@ -227,15 +228,15 @@ Key fields: `ts` (ISO timestamp), `method` (HTTP method, e.g. `GET`, `POST`), `u
227
228
  Assistant: I'll inspect the real site first if needed, but before I finish I'll create `target-workflow.ts` so the task produces reusable automation code.
228
229
  Assistant: [Runs `npx libretto open https://target.example.com --headed`]
229
230
  Assistant: [Reads `references/site-security-review.md` before choosing between passive network inspection, direct browser fetch calls, and Playwright-first automation]
230
- Assistant: [Runs `npx libretto snapshot --objective "Find the next required action" --context "We are starting the workflow from the landing page and need the first meaningful step."`]
231
+ Assistant: [Runs `npx libretto snapshot --session <session>`]
231
232
  Assistant: [Uses `snapshot` and `exec` as needed to understand the site and decide the implementation path]
232
233
  Assistant: [Reads `references/code-generation-rules.md` before writing production workflow code]
233
234
  Assistant: I found the working path. I'll now create the workflow file and verify it.
234
235
  Assistant: [Creates or edits `target-workflow.ts` following `references/code-generation-rules.md`]
235
- Assistant: [Runs `npx libretto run ./target-workflow.ts --headless --params '{"status":"open"}'` to validate]
236
+ Assistant: [Runs `npx libretto run ./target-workflow.ts --params '{"status":"open"}'` to validate]
236
237
  Assistant: Validation passed. Here are the results:
237
- [Shows the output/results from the headless run]
238
- To watch it yourself in a browser, run: npx libretto run ./target-workflow.ts --headed --params '{"status":"open"}'
238
+ [Shows the output/results from the validation run]
239
+ To run it again, use: npx libretto run ./target-workflow.ts --params '{"status":"open"}'
239
240
  </example>
240
241
  ```
241
242
 
@@ -245,25 +246,26 @@ To watch it yourself in a browser, run: npx libretto run ./target-workflow.ts --
245
246
  <example>
246
247
  [Context: The user has an existing Libretto workflow that is failing]
247
248
  Assistant: I'll reproduce the failure first so we can inspect the exact browser state it leaves behind.
248
- Assistant: [Runs `npx libretto run ./integration.ts --session debug-flow --headed`]
249
+ Assistant: [Runs `npx libretto run ./integration.ts --session debug-flow`]
249
250
  Assistant: The workflow failed and Libretto kept the browser open. I'll inspect the page state before changing code.
250
- Assistant: [Runs `npx libretto snapshot --session debug-flow --objective "Find the blocking error or broken selector target" --context "The workflow just failed after trying to continue from the review step, and I need to identify the visible blocker on the current page."`]
251
+ Assistant: [Runs `npx libretto snapshot --session debug-flow`]
251
252
  Assistant: [Runs `npx libretto exec --session debug-flow "...focused inspection or prototype..."`]
252
253
  Assistant: [Reads `references/code-generation-rules.md` before patching the workflow file]
253
254
  Assistant: I found the issue. I'll patch the workflow code and verify.
254
255
  Assistant: [Edits `integration.ts` following `references/code-generation-rules.md`]
255
- Assistant: [Runs `npx libretto run ./integration.ts --headless` to validate the fix]
256
+ Assistant: [Runs `npx libretto run ./integration.ts` to validate the fix]
256
257
  Assistant: Fix verified. Here are the results:
257
- [Shows the output/results from the headless run]
258
- To watch it yourself in a browser, run: npx libretto run ./integration.ts --headed
258
+ [Shows the output/results from the validation run]
259
+ To run it again, use: npx libretto run ./integration.ts
259
260
  </example>
260
261
  ```
261
262
 
262
263
  ## References
263
264
 
264
- - Read `references/configuration-file-reference.md` when you need to inspect or change `.libretto/config.json` for snapshot model selection or viewport defaults.
265
+ - Read `references/configuration-file-reference.md` when you need to inspect or change `.libretto/config.json` for viewport or session defaults.
265
266
  - Read `references/site-security-review.md` before reviewing the site's security posture and deciding whether to lead with network requests, passive interception, or Playwright DOM automation on a new site.
266
267
  - Read `references/code-generation-rules.md` before writing or editing production workflow files.
267
268
  - Read `references/auth-profiles.md` when auth-profile behavior is relevant.
268
269
  - Read `references/pages-and-page-targeting.md` when a session has multiple open pages or you need `--page`.
269
270
  - Read `references/action-logs.md` for full action log field descriptions and user-vs-agent event semantics.
271
+ - If the workflow code is deployed to the Libretto Cloud platform and you need to reference its API docs, fetch [https://libretto.sh/docs/llms.txt](https://libretto.sh/docs/llms.txt) and follow the relevant page links.
@@ -117,6 +117,12 @@ Do not rely on broad DOM querying inside `page.evaluate()` for production flows
117
117
 
118
118
  ## Network Request Methods
119
119
 
120
+ Network request methods are for active fetch/XHR endpoints the site already uses. Prefer them for data extraction or form submissions when the security review shows the path is safe and workable.
121
+
122
+ Before codifying a network request, confirm that the browser primitive matches how the site normally makes that request. Use `page.goto()` or link clicks for document navigation. Use `page.evaluate(fetch)` only for endpoints the site calls with fetch/XHR. Let the DOM load scripts, images, stylesheets, and iframes naturally, or create the corresponding DOM element if you truly need that request type.
123
+
124
+ Do not use `fetch()` to avoid UI navigation for page HTML or asset URLs. The request still comes from the browser, but the browser marks it as fetch/XHR with different request-context headers than a navigation, script, image, stylesheet, or iframe load. Do not try to fix that by copying headers, because the browser controls the request context. Prefer passive network interception when the site's own UI already triggers the useful request.
125
+
120
126
  When codifying network-based data extraction or form submissions, wrap `page.evaluate(() => fetch(...))` calls in typed methods on a shared API client class:
121
127
 
122
128
  ```typescript
@@ -1,25 +1,26 @@
1
1
  # Configuration File Reference
2
2
 
3
- Use this reference when you need to inspect or change the workspace configuration that powers `snapshot` analysis and default viewport behavior.
3
+ Use this reference when you need to inspect or change workspace configuration for default browser behavior.
4
4
 
5
5
  ## When to Use This
6
6
 
7
- - You want to confirm which AI model `snapshot` will use.
8
7
  - You want to understand where Libretto stores workspace-level settings.
9
8
  - You want a persistent default viewport for `open` or `run`.
9
+ - You want a persistent default browser provider, such as Kernel or Browserbase.
10
10
 
11
11
  ## File Location
12
12
 
13
13
  Libretto reads workspace config from `.libretto/config.json`.
14
14
 
15
- - The file is created by `npx libretto setup` during first-time onboarding (auto-pins the default model for the detected provider) or by `npx libretto ai configure ...` for explicit overrides.
16
- - API credentials come from your shell environment or a `.env` file **at the repository root** (next to your `.git` directory). The config file stores the selected model, not the secret itself. Set `LIBRETTO_DISABLE_DOTENV=1` to skip `.env` loading (useful in CI).
17
- - Use `npx libretto status` to inspect the current AI configuration and open sessions without changing anything.
15
+ - The file is created by `npx libretto setup` during first-time onboarding.
16
+ - Use `npx libretto status` to inspect open sessions without changing anything.
18
17
  - For first-time setup instructions, follow the main `SKILL.md` flow instead of expanding this reference.
19
18
 
20
19
  ## Supported Settings
21
20
 
22
- - `snapshotModel` selects the configured analysis model for `snapshot`.
21
+ - `provider` is an optional top-level setting used by `open` and `run` when you do not pass `--provider` and do not set `LIBRETTO_PROVIDER`. Must be `"local"`, `"kernel"`, `"browserbase"`, or `"libretto-cloud"`.
22
+ - Provider precedence is: CLI `--provider`, then `LIBRETTO_PROVIDER`, then `.libretto/config.json`, then `"local"`.
23
+ - Provider credentials belong in the repo root `.env` file, which Libretto loads automatically before running CLI commands.
23
24
  - `viewport` is an optional top-level setting used by `open` and `run` when you do not pass `--viewport`.
24
25
  - Viewport precedence is: CLI `--viewport`, then `.libretto/config.json`, then the default `1366x768`.
25
26
  - `sessionMode` sets the default session access mode for new sessions created by `open`, `connect`, and `run`. Must be `"read-only"` or `"write-access"`. When omitted, defaults to `"write-access"`. Pass `--read-only` or `--write-access` to `open`, `connect`, or `run` to override when creating a session.
@@ -29,7 +30,7 @@ Example:
29
30
  ```json
30
31
  {
31
32
  "version": 1,
32
- "snapshotModel": "openai/gpt-5.4",
33
+ "provider": "kernel",
33
34
  "viewport": {
34
35
  "width": 1280,
35
36
  "height": 800
@@ -41,15 +42,16 @@ Example:
41
42
  ## Common Commands
42
43
 
43
44
  ```bash
44
- npx libretto setup # first-time onboarding, auto-pins default model
45
- npx libretto status # inspect AI config and open sessions
46
- npx libretto ai configure openai # explicitly change provider/model
45
+ npx libretto setup # first-time onboarding
46
+ npx libretto status # inspect open sessions
47
+ npx libretto open https://example.com --provider kernel
48
+ npx libretto run ./integration.ts --provider browserbase
47
49
  npx libretto open https://example.com --viewport 1440x900
48
50
  npx libretto run ./integration.ts --viewport 1440x900
49
51
  ```
50
52
 
51
53
  ## Notes
52
54
 
55
+ - If you want a persistent default provider for the workspace, add `provider` to `.libretto/config.json` instead of repeating `--provider` on every command.
53
56
  - If you want a persistent default viewport for the workspace, add `viewport` to `.libretto/config.json` instead of repeating `--viewport` on every command.
54
- - If `snapshot` analysis is not configured yet, run `npx libretto setup` to auto-configure, or see the main `SKILL.md` flow.
55
- - Run `npx libretto status` at any time to check which model is active and whether credentials are present.
57
+ - Run `npx libretto status` at any time to check open sessions.
@@ -19,7 +19,7 @@ Use this reference when a Libretto session has multiple open pages and you need
19
19
  ```bash
20
20
  npx libretto pages --session debug-flow
21
21
  npx libretto exec --session debug-flow --page <page-id> "return await page.url()"
22
- npx libretto snapshot --session debug-flow --page <page-id> --objective "Find the active form"
22
+ npx libretto snapshot --session debug-flow --page <page-id>
23
23
  ```
24
24
 
25
25
  ## Notes
@@ -60,10 +60,11 @@ Use the review above to decide what is safe to prioritize. Every integration use
60
60
 
61
61
  ### Strategy A: Prioritize `page.evaluate(fetch(...))`
62
62
 
63
- Make fetch calls directly from within the browser's JavaScript context. The requests share the browser's TLS fingerprint, cookies, and origin. They look identical to requests the site's own JS would make.
63
+ Make fetch calls directly from within the browser's JavaScript context. Use this only for endpoints the site already calls with fetch/XHR, not for page navigation or asset loads.
64
64
 
65
65
  When to prioritize this:
66
66
 
67
+ - The target endpoint is normally called by the site with fetch/XHR
67
68
  - No enterprise bot protection is detected
68
69
  - `fetch` is not monkey-patched
69
70
  - The API responses are parseable and useful
@@ -71,7 +72,7 @@ When to prioritize this:
71
72
 
72
73
  Why: maximum control and efficiency. You call exactly the endpoints you want with the parameters you want, skip UI rendering, and get structured JSON back. On sites without aggressive detection, this is the fastest and cleanest approach.
73
74
 
74
- Risk: if the site monitors fetch call stacks, your calls may be flagged because they do not originate from the site's bundled code. This is uncommon but exists on high-security sites.
75
+ Risk: fetch is the wrong primitive for page HTML and asset URLs; use Playwright navigation or DOM-driven loads for those. Sites can also monitor fetch call stacks and flag calls that do not originate from the site's bundled code.
75
76
 
76
77
  You will still use Playwright for initial navigation, login/auth flows, cookie consent, and any UI interactions needed to establish session state before making fetch calls.
77
78
 
@@ -111,10 +112,9 @@ Trade-off: it is slower, more fragile against DOM changes, and you only get data
111
112
 
112
113
  | Site Profile | Primary Strategy | Supplement With |
113
114
  | --- | --- | --- |
114
- | No bot protection, fetch not patched | A (`page.evaluate(fetch)`) | Playwright for navigation/auth |
115
- | No bot protection, fetch is patched | B (`page.on('response', ...)`) | Playwright for navigation; DOM extraction as fallback |
116
- | Bot protection detected, fetch not patched | B (`page.on('response', ...)`) | Playwright for navigation; cautious use of `page.evaluate(fetch)` only if needed |
117
- | Bot protection detected, fetch is patched | B (`page.on('response', ...)`) | Playwright for navigation; DOM extraction as fallback |
115
+ | No bot protection, fetch/XHR endpoint, fetch not patched | A (`page.evaluate(fetch)`) | Playwright for navigation/auth |
116
+ | No bot protection, fetch is patched or endpoint is not fetch/XHR | B (`page.on('response', ...)`) | Playwright for navigation; DOM extraction as fallback |
117
+ | Bot protection detected | B (`page.on('response', ...)`) | Playwright for navigation; cautious use of `page.evaluate(fetch)` only if needed |
118
118
  | Server-rendered content (no API calls) | C (DOM extraction) | Playwright for all interaction |
119
119
 
120
120
  ## Output: Site Assessment Summary
@@ -4,7 +4,7 @@ description: "Read-only Libretto workflow for diagnosing live browser state with
4
4
  license: MIT
5
5
  metadata:
6
6
  author: saffron-health
7
- version: "0.6.12"
7
+ version: "0.6.14"
8
8
  ---
9
9
 
10
10
  ## How Libretto Read-Only Works
@@ -49,14 +49,7 @@ npx libretto pages --session failed-job-debug
49
49
  ### `snapshot`
50
50
 
51
51
  - Use `snapshot` as the first high-level observation tool.
52
- - Always provide both `--objective` and `--context`.
53
-
54
- ```bash
55
- npx libretto snapshot \
56
- --session failed-job-debug \
57
- --objective "Identify the visible failure state and likely blocking UI condition" \
58
- --context "The workflow already failed and the preserved browser must remain read-only."
59
- ```
52
+ - Run `snapshot <ref>` to inspect a subtree from the latest full snapshot.
60
53
 
61
54
  ### `readonly-exec`
62
55
 
package/src/cli/cli.ts CHANGED
@@ -1,6 +1,4 @@
1
- import { resolveAiSetupStatus } from "./core/ai-model.js";
2
1
  import { ensureLibrettoSetup } from "./core/context.js";
3
- import { librettoCommand } from "../shared/package-manager.js";
4
2
  import { createCLIApp } from "./router.js";
5
3
  import { warnIfInstalledSkillOutOfDate } from "./core/skill-version.js";
6
4
  import { loadEnv } from "../shared/env/load-env.js";
@@ -17,28 +15,6 @@ Docs (agent-friendly): https://libretto.sh/docs
17
15
 
18
16
  function printSetupAudit(): void {
19
17
  warnIfInstalledSkillOutOfDate();
20
-
21
- const status = resolveAiSetupStatus();
22
- switch (status.kind) {
23
- case "ready":
24
- console.log(`✓ Snapshot model: ${status.model}`);
25
- break;
26
- case "configured-missing-credentials":
27
- console.log(
28
- `✗ ${status.provider} configured (model: ${status.model}), but credentials are missing. Run \`${librettoCommand("setup")}\` to repair.`,
29
- );
30
- break;
31
- case "invalid-config":
32
- console.log(
33
- `✗ AI config is invalid. Run \`${librettoCommand("setup")}\` to reconfigure.`,
34
- );
35
- break;
36
- case "unconfigured":
37
- console.log(
38
- `✗ No AI model configured. Run \`${librettoCommand("setup")}\` or \`${librettoCommand("ai configure")}\` to set up.`,
39
- );
40
- break;
41
- }
42
18
  }
43
19
 
44
20
  function isRootHelpRequest(rawArgs: readonly string[]): boolean {
@@ -1,15 +1,15 @@
1
1
  /**
2
- * Experimental auth commands for the libretto hosted platform.
2
+ * Hosted-platform auth commands.
3
3
  *
4
- * libretto experimental auth signup
5
- * libretto experimental auth login
6
- * libretto experimental auth logout
7
- * libretto experimental auth invite <email> [--role member|admin|owner]
8
- * libretto experimental auth accept-invite <tenantSlug> <invitationId>
9
- * libretto experimental auth api-key issue [--label <label>]
10
- * libretto experimental auth api-key list
11
- * libretto experimental auth api-key revoke <id>
12
- * libretto experimental auth whoami
4
+ * libretto cloud auth signup
5
+ * libretto cloud auth login
6
+ * libretto cloud auth logout
7
+ * libretto cloud auth invite <email> [--role member|admin|owner]
8
+ * libretto cloud auth accept-invite <tenantSlug> <invitationId>
9
+ * libretto cloud auth api-key issue [--label <label>]
10
+ * libretto cloud auth api-key list
11
+ * libretto cloud auth api-key revoke <id>
12
+ * libretto cloud auth whoami
13
13
  *
14
14
  * Credentials live at ~/.libretto/auth.json (mode 0600). The CLI sends either
15
15
  * the stored API key or the stored session cookie depending on what's
@@ -17,15 +17,15 @@
17
17
  */
18
18
 
19
19
  import { z } from "zod";
20
- import { SimpleCLI } from "../framework/simple-cli.js";
20
+ import { SimpleCLI } from "affordance";
21
21
  import {
22
22
  ApiCallError,
23
23
  betterAuthCall,
24
- HOSTED_API_URL,
25
24
  NOT_AUTHENTICATED_MESSAGE,
26
25
  orpcCall,
27
26
  pickCredential,
28
27
  resolveApiUrl,
28
+ resolveHostedApiUrl,
29
29
  } from "../core/auth-fetch.js";
30
30
  import {
31
31
  authStatePath,
@@ -198,11 +198,10 @@ async function issueApiKey(
198
198
 
199
199
  export const signupCommand = SimpleCLI.command({
200
200
  description: "Create a new hosted-platform account and organization",
201
- experimental: true,
202
201
  })
203
202
  .input(SimpleCLI.input({ positionals: [], named: {} }))
204
203
  .handle(async () => {
205
- const apiUrl = HOSTED_API_URL;
204
+ const apiUrl = resolveHostedApiUrl();
206
205
  console.log("Sign up for libretto cloud");
207
206
  console.log();
208
207
  console.log("Heads up: a libretto user can only belong to one organization.");
@@ -215,7 +214,7 @@ export const signupCommand = SimpleCLI.command({
215
214
  const name = await prompt("Your name:");
216
215
  if (name.toLowerCase() === "q" || name.length === 0) {
217
216
  console.log(
218
- "OK — ask an existing teammate to run `libretto experimental auth invite <your-email>` and then run `libretto experimental auth accept-invite <slug> <invitation-id>` from this machine.",
217
+ "OK — ask an existing teammate to run `libretto cloud auth invite <your-email>` and then run `libretto cloud auth accept-invite <slug> <invitation-id>` from this machine.",
219
218
  );
220
219
  return;
221
220
  }
@@ -294,7 +293,7 @@ export const signupCommand = SimpleCLI.command({
294
293
  console.log(`Session saved to ${authStatePath()}`);
295
294
  console.log();
296
295
  console.log("To generate an API key, run:");
297
- console.log(" libretto experimental auth api-key issue --label <label>");
296
+ console.log(" libretto cloud auth api-key issue --label <label>");
298
297
  console.log("Then add LIBRETTO_API_KEY=<key> to your project's .env file.");
299
298
  });
300
299
 
@@ -304,11 +303,10 @@ export const signupCommand = SimpleCLI.command({
304
303
 
305
304
  export const loginCommand = SimpleCLI.command({
306
305
  description: "Sign in to an existing hosted-platform account",
307
- experimental: true,
308
306
  })
309
307
  .input(SimpleCLI.input({ positionals: [], named: {} }))
310
308
  .handle(async () => {
311
- const apiUrl = HOSTED_API_URL;
309
+ const apiUrl = resolveHostedApiUrl();
312
310
 
313
311
  const email = await prompt("Email:");
314
312
  const password = await promptPassword("Password:");
@@ -375,7 +373,6 @@ export const loginCommand = SimpleCLI.command({
375
373
 
376
374
  export const logoutCommand = SimpleCLI.command({
377
375
  description: "Clear local libretto credentials",
378
- experimental: true,
379
376
  })
380
377
  .handle(async () => {
381
378
  const state = await readAuthState();
@@ -400,7 +397,6 @@ export const logoutCommand = SimpleCLI.command({
400
397
 
401
398
  export const inviteCommand = SimpleCLI.command({
402
399
  description: "Invite a teammate to your active organization",
403
- experimental: true,
404
400
  })
405
401
  .input(
406
402
  SimpleCLI.input({
@@ -475,7 +471,7 @@ export const inviteCommand = SimpleCLI.command({
475
471
  console.log();
476
472
  console.log("Tell them to run:");
477
473
  console.log(
478
- ` libretto experimental auth accept-invite ${orgSlug} ${data.id}`,
474
+ ` libretto cloud auth accept-invite ${orgSlug} ${data.id}`,
479
475
  );
480
476
  });
481
477
 
@@ -485,7 +481,6 @@ export const inviteCommand = SimpleCLI.command({
485
481
 
486
482
  export const acceptInviteCommand = SimpleCLI.command({
487
483
  description: "Accept an organization invitation",
488
- experimental: true,
489
484
  })
490
485
  .input(
491
486
  SimpleCLI.input({
@@ -514,7 +509,7 @@ export const acceptInviteCommand = SimpleCLI.command({
514
509
  )
515
510
  .handle(async ({ input }) => {
516
511
  const stored = await readAuthState();
517
- const apiUrl = HOSTED_API_URL;
512
+ const apiUrl = resolveHostedApiUrl();
518
513
  const credential = pickCredential(stored);
519
514
  const expectedTenantSlug = input.tenantSlug;
520
515
 
@@ -535,7 +530,7 @@ export const acceptInviteCommand = SimpleCLI.command({
535
530
  [
536
531
  "You're already a member of an organization.",
537
532
  "A libretto user can only belong to one organization at a time.",
538
- "To accept this invite: log out, delete the existing account, and re-run `auth accept-invite` with a new account (or a fresh email).",
533
+ "To accept this invite: log out, delete the existing account, and re-run `libretto cloud auth accept-invite` with a new account (or a fresh email).",
539
534
  ].join("\n"),
540
535
  );
541
536
  }
@@ -611,7 +606,7 @@ export const acceptInviteCommand = SimpleCLI.command({
611
606
  console.log();
612
607
  console.log("Email verified. You're logged in and a member of the organization.");
613
608
  console.log("To generate an API key, run:");
614
- console.log(" libretto experimental auth api-key issue --label <label>");
609
+ console.log(" libretto cloud auth api-key issue --label <label>");
615
610
  console.log("Then add LIBRETTO_API_KEY=<key> to your project's .env file.");
616
611
  });
617
612
 
@@ -621,7 +616,6 @@ export const acceptInviteCommand = SimpleCLI.command({
621
616
 
622
617
  export const apiKeyIssueCommand = SimpleCLI.command({
623
618
  description: "Issue a new API key for the active organization",
624
- experimental: true,
625
619
  })
626
620
  .input(
627
621
  SimpleCLI.input({
@@ -658,7 +652,6 @@ export const apiKeyIssueCommand = SimpleCLI.command({
658
652
 
659
653
  export const apiKeyListCommand = SimpleCLI.command({
660
654
  description: "List API keys for the active organization",
661
- experimental: true,
662
655
  })
663
656
  .handle(async () => {
664
657
  const stored = await readAuthState();
@@ -691,13 +684,12 @@ export const apiKeyListCommand = SimpleCLI.command({
691
684
 
692
685
  export const apiKeyRevokeCommand = SimpleCLI.command({
693
686
  description: "Revoke an API key by id",
694
- experimental: true,
695
687
  })
696
688
  .input(
697
689
  SimpleCLI.input({
698
690
  positionals: [
699
691
  SimpleCLI.positional("id", z.string().min(1), {
700
- help: "API key id (from `auth api-key list`).",
692
+ help: "API key id (from `libretto cloud auth api-key list`).",
701
693
  }),
702
694
  ],
703
695
  named: {},
@@ -720,7 +712,7 @@ export const apiKeyRevokeCommand = SimpleCLI.command({
720
712
 
721
713
  console.log(`API key ${input.id} revoked.`);
722
714
  console.log(
723
- "If this key was in your .env, remove the LIBRETTO_API_KEY value and issue a new one with `auth api-key issue --label <label>`.",
715
+ "If this key was in your .env, remove the LIBRETTO_API_KEY value and issue a new one with `libretto cloud auth api-key issue --label <label>`.",
724
716
  );
725
717
  });
726
718
 
@@ -730,7 +722,6 @@ export const apiKeyRevokeCommand = SimpleCLI.command({
730
722
 
731
723
  export const whoamiCommand = SimpleCLI.command({
732
724
  description: "Print the active session and credential source",
733
- experimental: true,
734
725
  })
735
726
  .handle(async () => {
736
727
  const stored = await readAuthState();
@@ -740,13 +731,13 @@ export const whoamiCommand = SimpleCLI.command({
740
731
 
741
732
  if (credential.source === "none") {
742
733
  console.log(
743
- "Not authenticated. Run `libretto experimental auth signup`, `login`, or set LIBRETTO_API_KEY in your env.",
734
+ "Not authenticated. Run `libretto cloud auth signup`, `libretto cloud auth login`, or set LIBRETTO_API_KEY in your env.",
744
735
  );
745
736
  return;
746
737
  }
747
738
 
748
739
  console.log(`Auth source: ${credential.source}`);
749
- console.log(`API URL: ${HOSTED_API_URL}`);
740
+ console.log(`API URL: ${resolveHostedApiUrl()}`);
750
741
  console.log(
751
742
  `LIBRETTO_API_KEY: ${envKey ? `set in env (${envKey.slice(0, 6)}…)` : "not set in env"}`,
752
743
  );
@@ -6,8 +6,8 @@
6
6
  * them switch between any of the configured Subscription Update
7
7
  * products (Free / Pro / Team).
8
8
  *
9
- * libretto experimental billing portal → Stripe Customer Portal
10
- * libretto experimental billing status → plan + usage + period end
9
+ * libretto cloud billing portal → Stripe Customer Portal
10
+ * libretto cloud billing status → plan + usage + period end
11
11
  *
12
12
  * `libretto init` is unchanged. New tenants start on Free automatically
13
13
  * (with a real Stripe Customer + Free Subscription created at signup).
@@ -15,7 +15,7 @@
15
15
  * Auth: requires a session cookie (or LIBRETTO_API_KEY).
16
16
  */
17
17
 
18
- import { SimpleCLI } from "../framework/simple-cli.js";
18
+ import { SimpleCLI } from "affordance";
19
19
  import {
20
20
  NOT_AUTHENTICATED_MESSAGE,
21
21
  orpcCall,
@@ -71,7 +71,6 @@ function formatLimit(limit: number | null): string {
71
71
 
72
72
  export const billingPortalCommand = SimpleCLI.command({
73
73
  description: "Open the libretto plans page (current plan + switch options)",
74
- experimental: true,
75
74
  })
76
75
  .handle(async () => {
77
76
  const { apiUrl, credential } = await requireAuth();
@@ -97,7 +96,6 @@ export const billingPortalCommand = SimpleCLI.command({
97
96
 
98
97
  export const billingStatusCommand = SimpleCLI.command({
99
98
  description: "Print the current plan, status, and browser-hour usage",
100
- experimental: true,
101
99
  })
102
100
  .handle(async () => {
103
101
  const { apiUrl, credential } = await requireAuth();