Repository navigation
Require whirl run, add -O overrides, block-hosts, and settings in reports - #47
Merged
Merged
Conversation
Files now run only through `whirl run`. `whirl checkout.whirl` and `whirl --headed checkout.whirl` fail with a hint to use `whirl run`, and `whirl` alone prints help. `--out DIR` names the output directory, with the same default `whirl-artifacts/`. `--artifacts` stays as a deprecated alias that warns and cannot be combined with `--out`. `--load-state` and `--save-state` replace `--storage` and `--save-storage`, which are now usage errors that name their replacements. The state file keeps its format. `--storage` silently replaced a file's `storage` option. `--load-state` is a command control instead, so it cannot be combined with a file's `storage` or `setup` option. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`whirl run` and `whirl check` take repeatable `-O key=value` arguments that set an `[Options]` key for every file, setup flows included. Settings resolve from the built-in default, then the file, then the command line. A value has the syntax of the file's `key: value` line, so locators and quoted values keep their meaning, and an unknown key or invalid value is a usage error before any browser starts. For a scalar key the last value wins. For `allow-hosts` and `snapshot-mask`, the values form a list that replaces the file's list, and an empty value clears it. `-O setup=` is rejected, because setup flows get the same options. `--base`, `--browser`, `--step-timeout`, `--entry-timeout`, and `--user-agent` now go through the same resolver, with their value taken literally. Supplying one of them and `-O` for the same key is an error. One module, lang::cli_options, owns this, so later commands can reuse it. It puts the command line's lines in place of the file's, marked with their source, so lint, the run, and reports read one list. `whirl check` therefore lints with the overrides in place, and a lint about a `-O` value has no line. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`[Options] block-hosts` blocks the hosts its globs match, with the glob rules of `allow-hosts`. A block wins over an allowance, including the implicit allowance of the base host. The shim checks one host policy for page requests, redirect hops, WebSockets, and `HTTP` entries, and it routes requests when either list is set. `-O block-hosts=` forms and clears a list like `allow-hosts`. Each blocked host now carries the rule that blocked it: the matching `block-hosts` glob, or `allow-hosts` when no allowed glob matched. The console, JUnit, and HTML reports show it, and the JSON report adds `blockedHostRules` beside the unchanged `blockedHosts`. This changes the `endFlow` result, so the shim moves to protocol 9. `browsersim-origin: build | recorded` is the first BrowserSim setting. Ordinary runs validate it and do not apply it, and list it as inactive when a file or `-O` sets it. Other `browsersim-` keys stay unknown. Every file whose options resolve lists its settings in the JSON and HTML reports: the value it ran with, masked like other output, where the value came from, and whether this engine applies it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Later BrowserSim work will consume the settings rules of `whirl run`. This draft ADR fixes what that work must follow: `whirl record` is the only recording command, `--engine` and `--browser` stay separate, a `*.sim.json` recording stores every effective setting and replay uses only those, and each written flow records to a sibling bundle named after its stem, with collisions and output-over-input paths rejected. It is a draft: it becomes binding when it is accepted. Its two open decisions, the privacy and matching option syntax and what happens when a bundle exists, do not block the CLI work. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A `-O` value is now literal text, as if quoted, the way the option flags
already took theirs: `-O 'user-agent=Whirl/1 (test)'` works without inner
quotes, and `#` and `{{` are part of the value. For a list option, each
`-O` gives one item, so a host list written as in a file is a usage error
that says to give each host its own `-O`. A `snapshot-mask` value stays a
locator written as in a file. An empty value for a single-value option is
a usage error.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`-O` now sets every option, so these four flags were an arbitrary subset of the 17 keys. Each is now a usage error that names its `-O` form, such as `-O base=URL`. `--browser` stays: the accepted recording ADR keeps it beside `--engine`, and `whirl doctor --browser` names browsers the same way. Tests, the example script, and the docs use `-O` instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> (cherry picked from commit e41e403)
This was referenced Oct 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #46.
This is phase 2 of the Whirl–BrowserSim delivery sequence: the CLI and settings rules. It does not integrate BrowserSim. It gives ordinary runs the agreed command line, and it gives later commands one shared way to resolve options.
This changes existing scripts. Whirl has no users to migrate yet, so there are no aliases except
--artifacts.Explicit
runand renamed flagswhirl checkout.whirlwhirl run checkout.whirlwhirl --artifacts DIR ...whirl run --out DIR ...whirl --storage app.json ...whirl run --load-state app.json ...whirl --save-storage app.json ...whirl run --save-state app.json ...whirl --base URL --step-timeout 15s ...whirl run -O base=URL -O step-timeout=15s ...whirl checkout.whirlandwhirl --headed checkout.whirlfail with a hint to usewhirl run.whirlalone prints help and exits 4.--outdefaults towhirl-artifacts/, as before.--artifactsstill works and prints a deprecation warning. Supplying both is an error.--storageand--save-storagefail with a message that names the new flag. The state file format does not change; SPEC section 13 documents it.--load-statecannot be combined with a file'sstorageorsetupoption. The old--storagesilently replaced the file'sstorageoption.-O key=valuewhirl runandwhirl checktake repeatable-Oarguments that set an[Options]key for every file, setup flows included:whirl run checkout.whirl -O browser=firefox -O step-timeout=15s whirl run flows/ -O block-hosts=analytics.example.com -O block-hosts=*.analytics.example.com whirl run flows/ -O allow-hosts= whirl check checkout.whirl -O model=anthropic/claude-sonnet-5snapshot-maskvalue is the exception: it is a locator, written as in a file.-Oitems replace the file's list, and an empty value clears it.-O setup=are usage errors, found before any browser starts.--browseris the one flag left that sets an option. It goes through the same resolver, and--browsertogether with-O browser=is an error, even when the values agree.--base,--step-timeout,--entry-timeout, and--user-agentare removed; each fails with a message that names its-Oform.whirl checklints with the overrides in place, and still launches no browser. A lint about a-Ovalue has no line.One module,
lang::cli_options, owns this, so later commands can reuse it. It puts the command line's option lines in place of the file's, marked with their source.block-hosts,browsersim-origin, and settings in reports[Options] block-hostsblocks the hosts its globs match, with the glob rules ofallow-hosts. A block wins over an allowance, including the base host's implicit allowance. It applies to page requests, redirect hops, WebSockets, andHTTPentries.blocked host: localhost (not in allow-hosts). The JSON report addsblockedHostRules;blockedHostsis unchanged.browsersim-origin: build | recordedis checked but not used by ordinary runs. When a file or-Osets it, the console and reports list it as inactive. Otherbrowsersim-keys stay unknown.endFlownow returns a rule with each blocked host. Installed bundles needwhirl install.Recording contract
The accepted ADR
recording-settings-and-bundlesfixes what later recording work must follow.whirl recordis the only recording command.--engineand--browserstay separate. A*.sim.jsonrecording stores every effective setting, and replay uses only those. Each written flow records to a sibling bundle named after its stem. It adds no commands.Commits
whirl run, and rename the output and state flags.-O key=value.block-hosts, an inactivebrowsersim-origin, and settings in reports.-Ovalue as one literal item.--base,--step-timeout,--entry-timeout, and--user-agent.Validation
mise run checkpasses after each commit.-Oerror.-Oacross two flows: the last value wins, and list items replace or clear the file's list.block-hostsalone,block-hostswithallow-hosts, and blocking the base host, for page requests and anHTTPentry.browsersim-origin, and effective settings that keep anenv.*user agent out of the console, JSON, and HTML output.--out, and the--artifactsalias.🤖 Generated with Claude Code