ruby_llm-browser 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e6184d0ab1ce52e3a77ed427ff4e083790a7d573a51b5ea07ddffeab034b356e
4
- data.tar.gz: c08d7fd335590fa99341551ce77ca6a8f8ec61662b3e63903308f56ea9ff05d6
3
+ metadata.gz: 20b730312da9ae14b8e3a17d386ecaa0034a38b1ac87515e89d2c6a4aa29e8d7
4
+ data.tar.gz: 7f27467a067bbf8e8712cfffe1a855ce85a21e563765658a142ca7c468297929
5
5
  SHA512:
6
- metadata.gz: 3f671bfe311dea830346ce657373b81f514c227eac636576f76fb962a4690a0e688fecb476d36ef83a288d02cdc28e0bd2f8fece092b00cd8925e57cae6b3509
7
- data.tar.gz: 0f11137930c35dc67cf7642db5152864fa5b101bb957bba24edeab974279c66f33e728766bb5005c29bb331b37989f09edbbaee70f461acf419ea31db9b4a209
6
+ metadata.gz: ec5d0517a3b4fa4b4fbd2a440fd52d59b173b2f2adb4674c96f9e667bbaa57276984f09f1292865adb662fc1595f9f73b63c32509b9bd9269a058366bfa24ce0
7
+ data.tar.gz: 13fea67455f9bdd9b49864752e69731b527958fbf06bd7ca0325a167345eaf115190cff9778247e8e526518fdef0b17c1fcb46f60346ab5c09508ca490f8cb35
data/CHANGELOG.md CHANGED
@@ -4,6 +4,21 @@ All notable changes to this project are documented here. The format is based on
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project aims to
5
5
  follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.2.0] - 2026-10-19
8
+
9
+ ### Added
10
+
11
+ - `RubyLLM::Browser.tools(context:, schema:)` builds fresh Inspect and Extract
12
+ instances for `chat.with_tools(*tools)`. It never includes Act or dispatches work.
13
+ - Agent validation commands, an offline development workbench, and desktop/mobile
14
+ Chrome workflows with fixture screenshots. Browser libraries are development-only.
15
+
16
+ ### Changed
17
+
18
+ - Doctor reports `mode: :offline`, `:live`, or `:unconfigured`. FakeBackend checks
19
+ skip Stagehand SDK and provider environment checks. Custom backends no longer
20
+ receive unrelated Stagehand credential warnings. Stagehand remains blocked.
21
+
7
22
  ## [0.1.0] - 2026-10-18
8
23
 
9
24
  ### Fixed
data/CONTRIBUTING.md CHANGED
@@ -19,17 +19,24 @@ Thanks for helping. This is an unofficial community extension for
19
19
 
20
20
  ```bash
21
21
  bin/setup # bundle install
22
+ bin/check # offline suite, lint, alternate bundles, and examples
22
23
  bundle exec rake # specs + rubocop
23
24
  bundle exec rspec # specs only
24
25
  bundle exec bundle-audit check --update
25
26
  bundle exec rubocop -A # autocorrect style
26
27
  ```
27
28
 
29
+ For the offline workbench, real Chrome tests, screenshots, and installed-package
30
+ checks, follow [development and testing](docs/_advanced/development-and-testing.md).
31
+
28
32
  ## Changing behaviour
29
33
 
30
34
  - Add a failing spec first, including the negative/denial case.
31
35
  - Update `CHANGELOG.md` under `Unreleased`.
32
- - Update `docs/SECURITY_MODEL.md` or `README.md` if a boundary or public API moved.
36
+ - Update the relevant site guide in `docs/` when a boundary or public API changes.
37
+ Record breaking changes in `docs/_reference/upgrading.md`. Keep the README brief;
38
+ use [the documentation index](docs/README.md) for source locations and
39
+ [the roadmap](docs/_reference/roadmap.md) for proposed release scope.
33
40
  - Keep runnable examples and the package's local links green in
34
41
  `spec/integration/documentation_spec.rb`.
35
42
  - Run both alternate bundles in `gemfiles/` when changing Tool or Rails integration.
data/README.md CHANGED
@@ -1,41 +1,31 @@
1
1
  # ruby_llm-browser
2
2
 
3
- An **unofficial community extension** for [RubyLLM](https://rubyllm.com), with an
4
- experimental adapter for the official [Stagehand Ruby SDK](https://github.com/browserbase/stagehand-ruby).
5
- It provides read-only `Inspect` and schema-pinned `Extract` tools, operation bookkeeping,
6
- and an optional Rails 8 adapter. It does not implement a browser engine.
3
+ An unofficial [RubyLLM](https://rubyllm.com) extension for read-only browser inspection
4
+ and schema-checked extraction, with an optional Rails 8 adapter.
7
5
 
8
- The first release supports the offline `FakeBackend` only. `StagehandBackend` is present
9
- for future qualification, but it refuses live operations until browser-side egress and
10
- provider cleanup are qualified.
6
+ **0.2.0 supports offline use only.** `FakeBackend` runs without credentials or network
7
+ requests. The experimental Stagehand adapter refuses live operations; `Act` is an
8
+ offline simulation. This project is not maintained or endorsed by RubyLLM or Browserbase.
11
9
 
12
- > **Version 0.1.0 is the offline-only first release.** The built-in Stagehand backend
13
- > is unsupported, and the full live Act approval protocol is deferred. No live provider
14
- > calls were made. See the [release audit](docs/RELEASE_AUDIT.md). This project is not
15
- > maintained or endorsed by RubyLLM or Browserbase.
10
+ [Documentation](https://rubyllm-browser.wangyaodi.com/) ·
11
+ [Getting started](https://rubyllm-browser.wangyaodi.com/getting-started/) ·
12
+ [Roadmap to 1.0](docs/_reference/roadmap.md)
16
13
 
17
14
  ## Install
18
15
 
19
- Add the gem to your application's Gemfile:
16
+ Use Ruby 3.2+ and RubyLLM 2.x. Add to your Gemfile, then run `bundle install`:
20
17
 
21
18
  ```ruby
22
- gem "ruby_llm-browser", "~> 0.1.0"
19
+ gem "ruby_llm-browser", "~> 0.2.0"
23
20
  ```
24
21
 
25
- The core requires Ruby 3.2+, RubyLLM `>= 2.0, < 3`, `json_schemer ~> 2.5`, and
26
- `stagehand ~> 3.21.0`, plus patched DNS/URL/CGI/compression gems (see the
27
- [dependency reference](docs/API.md)). Requiring `ruby_llm/browser` loads neither Rails nor the Stagehand
28
- client, discovers no provider credentials, and opens no browser session.
29
-
30
22
  ## Try it offline
31
23
 
32
- This complete example makes no network request and requires no API key:
33
-
34
24
  ```ruby
35
25
  # smoke-test: offline
36
26
  require "ruby_llm/browser"
37
27
 
38
- # Fake DNS is only for this offline demonstration. Production uses real DNS.
28
+ # Test resolver for this offline example only.
39
29
  class OfflineResolver
40
30
  def getaddresses(_host) = [ "93.184.216.34" ]
41
31
  end
@@ -49,91 +39,30 @@ context = RubyLLM::Browser::Context.new(
49
39
  operation_store: RubyLLM::Browser::InMemoryOperationStore.new
50
40
  )
51
41
  schema = {
52
- "type" => "object",
53
- "properties" => { "title" => { "type" => "string" } },
42
+ "type" => "object", "properties" => { "title" => { "type" => "string" } },
54
43
  "required" => [ "title" ], "additionalProperties" => false
55
44
  }
56
-
57
- inspect_tool = RubyLLM::Browser::Inspect.new(context: context)
58
- extract_tool = RubyLLM::Browser::Extract.new(context: context, schema: schema)
45
+ inspect_tool, extract_tool = RubyLLM::Browser.tools(context: context, schema: schema)
59
46
  puts inspect_tool.execute(url: "https://docs.example.com/")[:status] # => ok
60
47
  puts extract_tool.execute(url: "https://docs.example.com/")[:data] # => {"title"=>"Example"}
61
48
  ```
62
49
 
63
- Register these instances on your configured RubyLLM chat with
64
- `chat.with_tools(inspect_tool, extract_tool)`. Never register `Act` by default.
65
- The host supplies authenticated **string** actor/run IDs, authorization, consent,
66
- the pinned extraction schema, budgets, and the backend.
67
-
68
- The tools return a **Hash**, not a `Result` object. Direct `Engine` calls return a
69
- `Result`. Check `status` and `error`; page data is untrusted evidence, not verified truth.
70
-
71
- ## Safety boundaries
72
-
73
- - URL policy checks hosts, schemes, ports, and public DNS/IP addresses. It cannot
74
- sandbox a remote browser or control page-triggered requests.
75
- - No built-in live backend is supported in this release. `StagehandBackend` always
76
- reports egress as unverified and refuses live operations. A host assertion cannot
77
- enable it.
78
- - The model cannot increase the host's output limit. Results are redacted, schema-checked
79
- for extraction, and bounded by the policy and remaining operation bytes.
80
- - A durable operation is claimed before start. Duplicate jobs cannot start it again.
81
- SDK retries are disabled; uncertain outcomes are never automatically replayed.
82
- - Cancellation fences workers but cannot undo an in-flight request. Dispatched operations
83
- retain quota until cleanup is confirmed. Run a reaper independently of job workers.
84
- - `max_cost_usd` is advisory metadata, not an enforced billing cap. Provider timeouts and
85
- cleanup are also not a promise of zero future charges.
86
- - `Act` is an offline simulation only. The full same-session live approval protocol is
87
- deferred to a later version. Candidate-list hashes and selector keyword filters are
88
- not proof of target identity or action safety.
89
-
90
- ## Rails integration
91
-
92
- Add Rails 8's `activerecord` and `activejob` to your host application, then opt in:
50
+ Register these tools on your configured chat with
51
+ `chat.with_tools(inspect_tool, extract_tool)`. The host owns identity, authorization,
52
+ source policy, schema, and budgets. Tool calls return hashes; page data remains untrusted.
93
53
 
94
- ```ruby
95
- require "ruby_llm/browser/rails"
96
- ```
54
+ ## Learn more
97
55
 
98
- ```bash
99
- bin/rails generate ruby_llm:browser:install
100
- bin/rails db:migrate
101
- ```
56
+ Use the [documentation site](https://rubyllm-browser.wangyaodi.com/) for configuration,
57
+ Rails jobs, API details, and security boundaries. The same guides ship as Markdown in
58
+ the gem; [docs/README.md](docs/README.md) indexes their source files.
102
59
 
103
- The adapter provides durable operation/approval stores, actor-scoped jobs, cancellation,
104
- and a reaper. Follow the [Rails guide](docs/RAILS.md) for the context factory, matching
105
- budgets, status access, scheduling, and upgrading an earlier development database.
106
- Only SQLite concurrency is tested locally; PostgreSQL requires its own qualification.
107
-
108
- ## Documentation
109
-
110
- - [Documentation website](https://rubyllm-browser.wangyaodi.com) (GitHub Pages)
111
- - [Documentation index](docs/README.md)
112
- - [API, configuration, and result reference](docs/API.md)
113
- - [Rails jobs and recovery](docs/RAILS.md)
114
- - [Security model and live qualification](docs/SECURITY_MODEL.md)
115
- - [Compatibility and release checklist](docs/RELEASING.md)
116
- - [Audit findings and unresolved blockers](docs/RELEASE_AUDIT.md)
117
- - [Requirement evidence](docs/WORK.md)
118
- - [Offline scripts](examples/)
119
-
120
- These documents and examples are included in the built gem.
121
-
122
- ## Development
123
-
124
- ```bash
125
- bin/setup
126
- bundle exec rake
127
- bundle exec bundle-audit check --update
128
- bundle exec ruby examples/plain_ruby.rb
129
- bundle exec ruby examples/rails_adapter.rb
130
- bundle exec rake build
131
- bundle exec ruby bin/verify-package --rails --audit
132
- ```
60
+ ## Contributing
133
61
 
134
- Tests block unmocked network requests. No paid live call or RubyGems publication is part
135
- of the default workflow. See [contributing](CONTRIBUTING.md).
62
+ Run `bin/setup`, then `bundle exec rake`. Tests block unmocked network requests.
63
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for development and
64
+ [the roadmap](docs/_reference/roadmap.md) for the next iterations.
136
65
 
137
66
  ## License
138
67
 
139
- MIT. See [LICENSE.txt](LICENSE.txt) and [third-party notices](NOTICE.md).
68
+ [MIT](LICENSE.txt). See [third-party notices](NOTICE.md).
data/docs/API.md CHANGED
@@ -1,177 +1,10 @@
1
1
  ---
2
- layout: default
3
- title: API and Configuration
4
- permalink: /api-and-configuration/
5
- description: Configure trusted host objects and interpret bounded untrusted results.
2
+ title: API Guide Location
3
+ description: Find the canonical API and configuration guide.
4
+ guide: false
6
5
  ---
7
6
 
8
7
  # API and configuration
9
8
 
10
- Configure trusted host objects and interpret bounded, untrusted results.
11
-
12
- After reading this guide, you will know:
13
-
14
- - How to register read-only tools.
15
- - Which inputs belong to the host and which belong to the model.
16
- - How to configure budgets, schemas, backends, and error handling.
17
-
18
- ## Creating a context
19
-
20
- Use the complete offline example in [Getting Started]({% link _getting_started/getting-started.md %}). `Context.new` requires:
21
-
22
- | Keyword | Type and meaning |
23
- | --- | --- |
24
- | `actor_id`, `run_id` | Nonempty strings from authenticated host records. Convert numeric database IDs with `to_s`. |
25
- | `backend` | A `Backend` instance. Use `FakeBackend` for offline tests. |
26
- | `source_policy` | A host-created `Policy`. |
27
- | `operation_store` | An `OperationStore`; durable storage is required across restarts or workers. |
28
- | `approval_store` | Optional `ApprovalStore`, needed only for experimental Act. |
29
- | `budget` | Optional `Budget`; defaults listed below. |
30
- | `clock` | Optional callable returning a UTC `Time`. |
31
- | `logger` | Optional host logger. Do not enable raw provider or tool payload logging. |
32
- | `consent` | Optional host consent record. The gem records its presence; it does not collect or authenticate consent. |
33
- | `metadata` | Optional host metadata. Never supply credentials here. |
34
-
35
- The host must reauthorize actor/run access when building a context, including background
36
- jobs. Passing IDs alone is not authentication. The model must never choose a backend,
37
- credential, schema, source allowlist, consent record, or budget.
38
-
39
- ## Registering tools
40
-
41
- ```ruby
42
- inspect_tool = RubyLLM::Browser::Inspect.new(context: context)
43
- extract_tool = RubyLLM::Browser::Extract.new(context: context, schema: schema)
44
- chat.with_tools(inspect_tool, extract_tool)
45
- ```
46
-
47
- Both tools expose `url`, optional `instruction`, and optional positive integer
48
- `max_bytes`. `max_bytes` can only tighten the policy and operation ceilings.
49
- `Extract` takes its schema in the constructor, not in model arguments.
50
-
51
- `Inspect` returns **candidate interactions**, not a screenshot or arbitrary page dump.
52
- Neither read-only tool dispatches candidates automatically. Pages may still run scripts
53
- and initiate requests; read-only does not mean browsing has no external effects.
54
-
55
- `Tool#execute` and RubyLLM `Tool#call` return a Hash. If you need a `Result` object, use:
56
-
57
- ```ruby
58
- engine = RubyLLM::Browser::Engine.new(context: context)
59
- result = engine.inspect(url: url)
60
- result = engine.extract(url: url, schema: schema, instruction: "Find the title")
61
- ```
62
-
63
- The optional `operation:` Engine keyword accepts a host-reserved operation with the
64
- same actor/run and budget. Starting it is an atomic reserved-to-starting claim. It is
65
- not a resume or retry API for active, unknown, or closed operations.
66
-
67
- ## Source policy
68
-
69
- `Policy.new(allowed_hosts: [...])` accepts exact hosts and `*.example.com` subdomains.
70
- A wildcard does not allow the bare domain. Defaults are HTTP/HTTPS and ports 80/443.
71
- Keep `verify_dns: true`; `resolver:` is injectable for offline fixtures.
72
-
73
- Other options are `allowed_schemes`, `allowed_ports`, `max_result_bytes` (65,536),
74
- `max_schema_depth` (8), `max_schema_properties` (64 root properties), and
75
- `max_schema_bytes` (16,384). Browser-side enforcement must also cover explicitly
76
- approved asset origins, redirects, frames, popups, WebSockets, and subresources.
77
-
78
- ## Extraction schemas
79
-
80
- Schemas must be bounded object JSON Schemas, passed as a Hash, JSON object string, or
81
- an object/class supporting `to_json_schema`. Supported keywords are `type`,
82
- `description`, `properties`, `required`, `items`, `enum`, `additionalProperties`,
83
- `title`, `minimum`, `maximum`, `minLength`, `maxLength`, `minItems`, `maxItems`,
84
- `format`, and `default`. Remote references and arbitrary schema extensions are refused.
85
-
86
- Use `required` and `additionalProperties: false` when an exact shape matters. Provider
87
- data must satisfy the schema before redaction or truncation. Invalid data returns
88
- `PROVIDER_ERROR`; it is not returned as a successful extraction. A truncated preview
89
- or redacted field need not retain the original schema's type. Always check the status.
90
-
91
- ## Results and errors
92
-
93
- `Result#to_h` contains symbol keys: `status`, `operation_id`, `final_url`,
94
- `captured_at` (UTC ISO 8601), `locator`, `digest`, `truncated`, `data`, and optional
95
- `error: { code:, message: }`. Locator/data objects use string keys. JSON encodes all
96
- keys as strings. Credential-like query values are redacted in URL provenance.
97
-
98
- Statuses are `ok`, `truncated`, `error`, `unknown`, and `cleanup_pending`.
99
- `Result#ok?` accepts `ok` and `truncated`; it makes no factual verification claim.
100
- `digest` is SHA-256 of canonical JSON of the returned, sanitized data. Very small byte
101
- limits can produce an empty string or scalar preview; `truncated` is authoritative.
102
-
103
- Engine preflight denials raise typed errors. Tools convert them into error Hashes.
104
- After a session starts, the Engine attempts cleanup and returns a failure result.
105
- Cleanup failure can supersede the original result with `cleanup_pending`; inspect the
106
- durable operation's `error_code` and arrange host review for unknown effects.
107
-
108
- Safe error codes: `INVALID_INPUT`, `NOT_AUTHORIZED`, `UNSUPPORTED_SECURITY_CAPABILITY`,
109
- `BUDGET_EXHAUSTED`, `SESSION_UNKNOWN`, `CLEANUP_PENDING`, `APPROVAL_REQUIRED`,
110
- `APPROVAL_STALE`, and `PROVIDER_ERROR`.
111
-
112
- ## Budgets
113
-
114
- `Budget.new` defaults to `max_seconds: 60`, `max_steps: 12`, `max_bytes: 262_144`,
115
- `max_concurrent: 1`, and `max_cost_usd: nil`.
116
-
117
- `RubyLLM::Browser.configure` sets process defaults for `default_budget`,
118
- `max_result_bytes`, `clock`, and `logger`. New contexts/policies use those defaults;
119
- existing objects do not change. `configuration.backend` is only a reserved host slot:
120
- contexts always require an explicitly supplied backend and never use a fallback.
121
-
122
- - Steps count navigation, observation, extraction, and action calls, not start/cleanup.
123
- - Bytes count retained sanitized result data, not all bytes the remote browser receives.
124
- - Wall-clock checks refuse new calls after expiry. Stagehand request timeouts are bounded
125
- by remaining time. Cleanup has a separate timeout and may outlive this budget.
126
- - Concurrency is scoped to the actor across runs. Unknown/pending cleanup holds a slot.
127
- - `max_cost_usd` is **advisory only**. There is no cost ledger or provider hard spending
128
- cap in this release. Enforce billing limits in the provider/host.
129
-
130
- ## Stagehand backend status
131
-
132
- `StagehandBackend` is unsupported for live operations in this release. It always reports
133
- `egress_isolation: :unverified` and `act_supported?: false`. `Engine` refuses it before
134
- the first provider request, and direct start, navigation, observation, extraction, and
135
- Act calls also fail closed. No constructor option or injected client enables live use.
136
-
137
- The adapter remains in the source for future qualification. Its client pins credentials
138
- and base URL, disables retries, self-healing, CAPTCHA solving, session recording and
139
- session logging, and requests a provider timeout. These controls do not prove egress,
140
- TTL, billing, final-URL reporting, or cleanup. `end_session` sends no request in this
141
- release and returns `false`; the operation remains `cleanup_pending`.
142
-
143
- The constructor accepts `server: :remote`, `base_url:`, `timeout: 60.0`,
144
- `custom_headers_approved: false`, `env: ENV`, and an injected `client:` for internal
145
- contract tests. A future live implementation must verify all relevant environment
146
- settings, egress across every browser request path, TTL and closure status, and provider
147
- billing controls before it can advertise support.
148
-
149
- ## Dependency security floors
150
-
151
- Old Ruby installations can supply vulnerable default gems even when a developer's
152
- lockfile audit passes. Runtime requirements explicitly exclude those versions:
153
- `cgi >= 0.4.2, < 1`, `resolv >= 0.7.2, < 1`, `uri >= 1.0.4, < 2`, and
154
- `zlib >= 3.2.3, < 4`. A fresh install may build native extensions for these gems.
155
- Use a supported, patched Ruby interpreter as well; these floors do not patch Ruby or
156
- system libraries. Audit the versions actually activated by your application, including
157
- default gems, not just a development lockfile.
158
-
159
- ## Experimental Act
160
-
161
- `Act.new(context:)` declares RubyLLM `requires_approval`. Its arguments are `url`,
162
- `approval_id`, `method`, `selector`, optional `description`, and optional `arguments`.
163
- The resolver reads the host store without consuming. Consumption immediately before
164
- dispatch checks actor/run, exact URL/action digest, expiry, and any supplied
165
- page/operation/session bindings. Revocation and consumption are atomic in the stores.
166
-
167
- **Do not use this as a production authorization protocol yet.** Bindings are currently
168
- optional; a candidate-list digest is not a DOM/target revision, and each Engine action
169
- opens a fresh session. The same-session host approval flow required by the specification
170
- is deferred to a later version. The Engine refuses all non-fake Act calls before starting
171
- a session. Selector/description keyword filters are defense in depth, not semantic proof
172
- that a click is harmless. The Stagehand adapter does not support Act in this release.
173
-
174
- ## Next steps
175
-
176
- - Read [Rails integration]({% link RAILS.md %}) for durable workers and recovery.
177
- - Read [security boundaries]({% link SECURITY_MODEL.md %}) before qualifying a live backend.
9
+ The [API and configuration reference](_reference/api-and-configuration.md) is the
10
+ canonical guide. Read it on the [documentation site](https://rubyllm-browser.wangyaodi.com/api-and-configuration/).
data/docs/RAILS.md CHANGED
@@ -1,167 +1,10 @@
1
1
  ---
2
- layout: default
3
- title: Rails Jobs and Recovery
4
- description: Run bounded read-only operations with durable state and independently scheduled cleanup.
2
+ title: Rails Guide Location
3
+ description: Find the canonical Rails jobs and recovery guide.
4
+ guide: false
5
5
  ---
6
6
 
7
7
  # Rails jobs and recovery
8
8
 
9
- Run bounded read-only operations with durable state and independently scheduled cleanup.
10
-
11
- After reading this guide, you will know:
12
-
13
- - How to install the adapter's tables.
14
- - How to build a freshly authorized job context with matching budgets.
15
- - How to inspect status, cancel work, and recover orphaned sessions.
16
-
17
- ## Installing the adapter
18
-
19
- Your application supplies Rails 8, Active Record, Active Job, and a database adapter.
20
- They are not runtime dependencies of the plain-Ruby gem.
21
-
22
- ```ruby
23
- require "ruby_llm/browser/rails"
24
- ```
25
-
26
- ```bash
27
- bin/rails generate ruby_llm:browser:install
28
- bin/rails db:migrate
29
- ```
30
-
31
- The generator creates operations, approvals, and per-actor reservation-lock tables.
32
- SQLite and PostgreSQL are accepted by the store, but only SQLite concurrency is tested
33
- locally. MySQL is not supported by this adapter's partial indexes/locking contract.
34
- Use a database timeout appropriate to your workload. Database lock failures fail closed;
35
- they must not be handled by retrying a browser call with a new operation ID.
36
-
37
- `Schema.create!` is for disposable fixtures, not production migrations or schema upgrades.
38
- The [offline Rails example](https://github.com/yorzi/ruby_llm-browser/blob/main/examples/rails_adapter.rb) requires no full Rails app.
39
-
40
- ## Configuring the trusted context factory
41
-
42
- ```ruby
43
- # config/initializers/ruby_llm_browser.rb
44
- require "ruby_llm/browser/rails"
45
-
46
- browser_budget = RubyLLM::Browser::Budget.new(max_seconds: 30, max_steps: 6)
47
- RubyLLM::Browser::Rails.context_factory = lambda do |actor_id:, run_id:|
48
- # Resolve authenticated host records and recheck authorization, consent and revocation.
49
- # Build policy/backend from those records, never from job or model-supplied credentials.
50
- RubyLLM::Browser::Context.new(
51
- actor_id: actor_id, run_id: run_id,
52
- backend: qualified_backend, source_policy: policy,
53
- operation_store: RubyLLM::Browser::Rails.operation_store,
54
- budget: browser_budget
55
- )
56
- end
57
- ```
58
-
59
- `qualified_backend` and `policy` above are host objects, not global APIs supplied by the
60
- gem. The factory must use the **same operation-store instance and budget limits** as
61
- the queued reservation. Construct different budgets per run only from trusted records
62
- that the factory can retrieve again. An optional approval store does not enable Act in
63
- jobs; `OperationJob` accepts only `inspect` and `extract`.
64
-
65
- ## Enqueuing a read-only operation
66
-
67
- ```ruby
68
- operation = RubyLLM::Browser::Rails::OperationJob.enqueue(
69
- actor_id: current_user.id.to_s, run_id: research_run.id.to_s,
70
- kind: :inspect, url: "https://docs.example.com/",
71
- budget: browser_budget, idempotency_key: "research-#{research_run.id}"
72
- )
73
- ```
74
-
75
- For extraction, pass `kind: :extract` and a host-pinned JSON `schema:`. Optional
76
- `instruction:` and `max_bytes:` have the same meaning as on the tools.
77
-
78
- One actor/run/key identifies one exact payload and budget. A changed payload using the
79
- same key is rejected. Repeated enqueue calls may add duplicate queue deliveries, but
80
- they attach to the same durable operation. Starting is atomically claimed once. A job
81
- that sees a started, unknown, pending-cleanup, or terminal operation cannot start it
82
- again. No automatic browser retry is configured.
83
-
84
- Reservation and queue insertion are separate transactions. If enqueueing fails, retain
85
- the returned operation identity when available and use the same idempotency key after
86
- investigation. Schedule the reaper to reclaim expired reservations that never started.
87
-
88
- Configure `RubyLLM::Browser::Rails.job_queue = :browser` if you need a separate queue.
89
- Jobs suppress argument logging, but queues still persist URLs, instructions and schemas.
90
- Protect queue access, storage, retention and encryption in the host application.
91
-
92
- ## Reading status and progress
93
-
94
- ```ruby
95
- store = RubyLLM::Browser::Rails.operation_store
96
- operation = store.fetch!(operation_id)
97
- # Authorize this read against the authenticated actor/run before returning anything.
98
- summary = operation.summary
99
- ```
100
-
101
- `summary` omits provider session IDs and budget internals. It reports state, steps,
102
- bytes, fence, timestamps, error code and cancellation flag. It is coarse progress,
103
- not a percentage-complete promise. No result body is durably stored by the job; the
104
- host must explicitly implement authorized result storage/delivery if needed. Do not
105
- rely on an Active Job return value after asynchronous execution.
106
-
107
- The stores are trusted server APIs, not tenant-safe controllers. They expose unscoped
108
- fetch/sweep methods for workers; never expose them directly to model arguments or HTTP.
109
- Tool progress callbacks are feature-detected on RubyLLM 2.1+, and contain no raw URL.
110
-
111
- ## Cancelling and reaping
112
-
113
- ```ruby
114
- store.cancel(operation_id, actor_id: current_user.id.to_s,
115
- run_id: research_run.id.to_s, now: Time.now.utc)
116
- RubyLLM::Browser::Rails::Reaper.new(backend: qualified_backend).sweep
117
- ```
118
-
119
- Cancellation of a never-started reservation is terminal immediately. Otherwise it sets
120
- `cancel_requested`, fences stale workers, and remains `cleanup_pending` with quota held.
121
- It cannot undo an in-flight provider request. A returned session ID is persisted even
122
- if cancellation raced with session creation.
123
-
124
- Run a reaper regularly in an independent scheduler, not only in the operation worker's
125
- ensure block. A reaper fences workers **before** reconciliation/cleanup, tries to end
126
- known sessions even when provider reconciliation is unavailable, and reports `failed`
127
- rather than claiming a database write succeeded. `ttl_seconds:` is an optional positive
128
- idle threshold, not proof that the provider's billable session has expired.
129
-
130
- Stagehand exposes no correlation endpoint here. An unknown start without a session ID
131
- remains unknown and holds quota until the host supplies provider-confirmed evidence.
132
- Alert on unknown/pending/failed entries. Never free quota just because enough local time
133
- passed. An unknown action outcome remains in the result/error code even if session
134
- cleanup succeeds; do not replay it.
135
-
136
- One reaper/backend instance must cover only operations belonging to that provider
137
- configuration. The current table has no backend credential-configuration binding.
138
- Multi-provider/multi-credential deployments need a host-scoped store or a future schema
139
- extension before a global sweep is safe.
140
-
141
- ## Upgrading an earlier development snapshot
142
-
143
- Nothing has been publicly released. If you already ran the earlier generator, preserve
144
- your data and add an explicit migration for these new fields instead of rerunning
145
- `create_table` or dropping the database:
146
-
147
- ```ruby
148
- class HardenBrowserBookkeeping < ActiveRecord::Migration[8.1]
149
- def change
150
- create_table :ruby_llm_browser_actors, id: :string do |t|
151
- t.integer :sequence, null: false, default: 0
152
- end
153
- add_column :ruby_llm_browser_operations, :cancel_requested, :boolean, default: false, null: false
154
- add_column :ruby_llm_browser_operations, :request_digest, :string
155
- end
156
- end
157
- ```
158
-
159
- Adapt this migration if any additions already exist. Drain workers during the upgrade.
160
- Legacy rows without request digests are not payload-bound, so do not reuse their
161
- idempotency keys for new work. Inspect earlier terminal cancellations for sessions that
162
- may not have been confirmed closed before reclaiming them.
163
-
164
- ## Next steps
165
-
166
- - Review [the API]({% link API.md %}) for result interpretation and budget semantics.
167
- - Review [release blockers]({% link RELEASE_AUDIT.md %}) before production deployment.
9
+ The [Rails integration guide](_advanced/rails-integration.md) is the canonical guide.
10
+ Read it on the [documentation site](https://rubyllm-browser.wangyaodi.com/rails-integration/).
data/docs/README.md CHANGED
@@ -1,16 +1,26 @@
1
1
  # Documentation
2
2
 
3
- Use these guides to configure browser tools and understand their limits.
3
+ Read the [documentation site](https://rubyllm-browser.wangyaodi.com/) for the latest
4
+ stable release. The [next-version site](https://rubyllm-browser.wangyaodi.com/next/)
5
+ follows `main`. The Markdown files below are the source for those guides and ship in
6
+ the gem.
4
7
 
5
- - [API reference](API.md): contexts, tools, schemas, results, budgets, and backend options.
6
- - [Rails integration](RAILS.md): durable stores, jobs, cancellation, recovery, and migrations.
7
- - [Security model](SECURITY_MODEL.md): trust boundaries and live deployment qualification.
8
- - [Release checklist](RELEASING.md): compatibility, package verification, and owner approvals.
9
- - [Release audit](RELEASE_AUDIT.md): findings, fixes, and remaining publication blockers.
10
- - [Owner action plan](RELEASE_ACTION_PLAN.md): decisions you own and work you can delegate.
11
- - [WORK ledger](WORK.md): exact commands and offline requirement evidence.
12
- - [Specification baseline](SPEC_BASELINE.md): product intent and governance boundaries.
8
+ - [Getting started](_getting_started/getting-started.md): installation and an offline example.
9
+ - [Configuration](_getting_started/configuration.md): host inputs and process defaults.
10
+ - [Inspect and Extract](_core_features/inspect-extract.md): tools and result handling.
11
+ - [Rails jobs and recovery](_advanced/rails-integration.md): installation, workers, and cleanup.
12
+ - [API and configuration reference](_reference/api-and-configuration.md): parameters and errors.
13
+ - [Security model](SECURITY_MODEL.md): guarantees and limits.
14
+ - [Roadmap to 1.0](_reference/roadmap.md): proposed versions and acceptance criteria.
13
15
 
14
- Start with the runnable offline example in the [README](../README.md). No guide grants
15
- authorization to access a source or spend provider credits. Gem releases use the reviewed
16
- tag workflow in [the release checklist](RELEASING.md).
16
+ ## Maintaining these docs
17
+
18
+ Keep the root README to installation, one example, and links. Put usage and API details
19
+ in the site guides, editing each topic in one place. Link to those source files when
20
+ writing repository Markdown; use Jekyll link tags between site pages. Keep
21
+ [CHANGELOG.md](../CHANGELOG.md) to shipped changes.
22
+
23
+ Preview with `docs/bin/serve.sh`; build with `docs/bin/build.sh`. See
24
+ [releasing](RELEASING.md) for package checks. The [0.1.0 audit](RELEASE_AUDIT.md),
25
+ [release record](RELEASE_ACTION_PLAN.md), [evidence ledger](WORK.md), and
26
+ [specification baseline](SPEC_BASELINE.md) preserve historical evidence.