Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
a4a6835
cleanup
rksm May 29, 2026
615d9aa
build(browser): add aws-config, aws-sdk-devicefarm, thirtyfour deps
rksm May 29, 2026
4b65ea5
test(browser): pin local command symbols before frontend extraction
rksm May 29, 2026
5f1dfb7
refactor(browser): add driver-agnostic BrowserDriver trait + Frontend…
rksm May 29, 2026
45e6b23
refactor(browser): move selectors + retarget commands to BrowserDrive…
rksm May 29, 2026
12648ec
refactor(browser): move HyperCore/HyperLite automation behind Browser…
rksm May 29, 2026
7328970
refactor(browser): drive Local backend through ChromiumDriver (no beh…
rksm May 29, 2026
2c96299
feat(browser): add WebDriverDriver (thirtyfour) BrowserDriver impl
rksm May 29, 2026
9b482ca
feat(config): add DeviceFarmConfig
rksm May 29, 2026
2e00441
feat(config): add AwsDeviceFarm participant backend kind
rksm May 29, 2026
d01ff23
feat(config): wire device_farm config into Config + defaults
rksm May 29, 2026
e5616eb
feat(browser): add TestGridApi seam over aws-sdk-devicefarm
rksm May 29, 2026
e42eb0f
feat(browser): implement DeviceFarmSession lifecycle + keep-alive poller
rksm May 29, 2026
922429e
feat(browser): wire AwsDeviceFarm backend into Participant::spawn
rksm May 29, 2026
befd16f
test(browser): integration test for Device Farm session lifecycle
rksm May 29, 2026
4a4474b
style: cargo fmt
rksm May 29, 2026
3f776d6
plan 1
rksm Jun 2, 2026
2b486c7
plan 2
rksm Jun 2, 2026
682eb92
headless mode
rksm Jun 2, 2026
0a10732
2026-06-02-new-video-constraints-support.org v1
rksm Jun 2, 2026
61b3e7f
2026-06-02-new-video-constraints-support.org v2
rksm Jun 2, 2026
f7166f3
Add video constraint support
rksm Jun 3, 2026
d651289
improved logging for headless mode
rksm Jun 3, 2026
e5e6433
nix flake update (for recent chrome version)
rksm Jun 3, 2026
5525886
Fix Chrome request extra info CDP parsing
rksm Jun 3, 2026
2b2a7cb
Fix local browser shutdown in headless mode
rksm Jun 3, 2026
acb3e72
Add headless simulator project skill
rksm Jun 3, 2026
7f01973
untrack 2026-06-01-no-tui-mode.md, 2026-06-02-new-video-constraints-s…
rksm Jun 3, 2026
5acc17c
device farm secrets
rksm Jun 3, 2026
cbaeafa
aws device farm: fix joining
rksm Jun 4, 2026
66d0745
secrets
rksm Jun 4, 2026
f34897f
Fix Device Farm state polling
rksm Jun 4, 2026
50b7923
embed device farm secrets
rksm Jun 4, 2026
289bbfb
cloudflare-browser-simulator is now a git submodule
rksm Jun 4, 2026
a6ea830
aws subcommand
rksm Jun 4, 2026
f5b8e14
update github workflows to use aws secrets
rksm Jun 4, 2026
a5c42ea
fix(config): drop unused device farm timeouts
rksm Jun 4, 2026
2cab0a7
feat(cli): support human durations for aws since
rksm Jun 4, 2026
1413742
ci: allow custom cargo-dist workflow
rksm Jun 4, 2026
42045f4
fix(deps): avoid legacy AWS rustls stack
rksm Jun 4, 2026
0a8052a
Fix participant shutdown cleanup race
rksm Jun 5, 2026
5875501
Fix headless participant cleanup races
rksm Jun 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion .codex/skills/release-hyper-browser-simulator/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Use this skill to prepare, publish, or verify releases of the Rust workspace in
- Generated release workflow: `.github/workflows/release.yml`.
- Local release helpers: `justfile`.
- User install docs: `README.md`.
- Cloudflare worker API schema: `cloudflare-browser-simulator` git submodule, using `cli/openapi/cloudflare-browser-simulator.json`.

Before making changes, check `git status --short --branch` and work with any existing dirty files without reverting unrelated user edits.

Expand All @@ -30,8 +31,16 @@ Homebrew:
- Release artifacts are hosted on GitHub.
- Formulae are pushed to `hypervideo/homebrew-tap`.
- CI needs the `HOMEBREW_TAP_TOKEN` secret on `hypervideo/browser-simulator`.
- CI and release checkouts need the `CLOUDFLARE_BROWSER_SIMULATOR_READ_TOKEN` secret on `hypervideo/browser-simulator`; it must be a read-only token that can fetch this public repo and the private `hypervideo/cloudflare-browser-simulator` submodule.
- Prerelease tags do not publish to Homebrew unless `publish-prereleases` is enabled.

Cloudflare worker submodule:

- The worker deploys from its own repository. Do not deploy the worker from this repo's release flow.
- The simulator release source must pin a worker submodule commit that is reachable from GitHub, not only from a local sibling checkout.
- If the submodule pointer references a worker commit that is not pushed yet, push that worker commit first. Use a non-`main` branch if deployment should not happen; the worker repo deploy workflow deploys from `main`.
- To consume a newer worker API, update and commit the worker repo's generated `cli/openapi/cloudflare-browser-simulator.json`, then update the submodule pointer here and make any Rust client compatibility fixes.

Nix:

- `flake.nix` exposes `.#hyper-client-simulator`, `.#client-simulator`, and `.#default`.
Expand All @@ -48,6 +57,8 @@ Nix:
git fetch --tags origin
git tag --sort=-v:refname | head
gh release list --repo hypervideo/browser-simulator --limit 10
git submodule update --init --recursive
git submodule status --recursive
```

2. Choose the next SemVer version, using a `v` prefix only for the git tag.
Expand All @@ -58,7 +69,18 @@ gh release list --repo hypervideo/browser-simulator --limit 10
- `nix/packages.nix`: `version = "X.Y.Z";`.
- `Cargo.lock`: refresh local package versions after the `Cargo.toml` bump.

4. Validate before tagging:
4. Confirm submodule release readiness:

```sh
git -C cloudflare-browser-simulator status --short --branch
git -C cloudflare-browser-simulator rev-parse HEAD
git -C cloudflare-browser-simulator fetch origin --tags
git -C cloudflare-browser-simulator branch -r --contains HEAD
```

The submodule should be clean and its commit must be contained by an `origin/*` ref before tagging. If no remote branch or tag is printed, push the worker commit first.

5. Validate before tagging:

```sh
just fmt
Expand Down Expand Up @@ -96,6 +118,8 @@ gh run list --repo hypervideo/browser-simulator --workflow Release --limit 10
gh release view vX.Y.Z --repo hypervideo/browser-simulator
```

If release checkout fails while fetching `cloudflare-browser-simulator`, confirm `CLOUDFLARE_BROWSER_SIMULATOR_READ_TOKEN` exists and can read the private worker repo, and confirm the pinned submodule commit has been pushed.

Check the Homebrew tap formula:

```sh
Expand Down
150 changes: 150 additions & 0 deletions .codex/skills/run-headless-simulator/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
---
name: run-headless-simulator
description: Run hyper-client-simulator participants from the CLI without the TUI. Use for agent-friendly headless smoke tests, multi-participant runs, and backend startup checks.
---

# Run Headless Simulator

## Overview

Use the `headless` subcommand when an agent or script needs to run simulator participants without the interactive TUI. In the repo, prefer the development command through Cargo; for an installed release, call the binary directly.

```sh
cargo run -- headless [OPTIONS]
hyper-client-simulator headless [OPTIONS]
```

Run from the Nix devshell when possible so Chromium, FFmpeg, native libraries, and the Rust toolchain match the repository environment.

## Basic Usage

Start one participant from global CLI settings:

```sh
cargo run -- headless \
--url https://latest.dev.hyper.video/0Y6-6FZ-20J \
--backend local \
--headless true \
--audio-enabled true \
--video-enabled true
```

Start one backend-only smoke test that does not require Chromium:

```sh
cargo run -- headless \
--url https://example.com/lite/demo \
--participant '{"backend":"remote-stub","audio_enabled":false}'
```

Start multiple participants by repeating `--participant`:

```sh
cargo run -- headless \
--url https://latest.dev.hyper.video/F27-T5F-DXY \
--participant '{"backend":"local","audio_enabled":false}' \
--participant '{"backend":"cloudflare","audio_enabled":true}'
```

## Configuration Model

- Global CLI flags apply to the base config loaded by the simulator.
- If no `--participant` values are passed, `headless` starts one participant from the effective global config.
- Each repeated `--participant` JSON value clones the effective global config and applies only that participant's overrides.
- CLI overrides and participant JSON overrides are in-memory only; `headless` does not persist them back to the config file.
- Logs print through normal tracing output rather than the TUI logger.
- First `Ctrl-C` requests shutdown and waits for participants to stop; a second `Ctrl-C` exits with code `130`.

## Options

Global CLI option names use kebab-case:

- `--url URL`
- `--backend BACKEND`
- `--headless true|false`
- `--audio-enabled true|false`
- `--video-enabled true|false`
- `--screenshare-enabled true|false`
- `--auto-gain-control true|false`
- `--noise-suppression MODEL`
- `--transport MODE`
- `--video-constraint-publish-webcam CONSTRAINT`
- `--video-constraint-subscribe CONSTRAINT`
- `--video-max-concurrent-tracks TRACKS`
- `--blur true|false`
- `--participant JSON`

Participant JSON field names use snake_case:

- `url`
- `backend`
- `headless`
- `audio_enabled`
- `video_enabled`
- `screenshare_enabled`
- `auto_gain_control`
- `noise_suppression`
- `transport`
- `video_constraint_publish_webcam`
- `video_constraint_subscribe`
- `video_max_concurrent_tracks`
- `blur`

Participant JSON denies unknown fields. Treat typos as command errors, not ignored settings.

## Values

Backend values:

- `local`
- `cloudflare`
- `remote-stub`
- `aws-device-farm`

Transport values:

- `webtransport`
- `webrtc`

Video constraint values:

- `none`
- `90p`
- `144p`
- `240p`
- `360p`
- `480p`
- `720p`
- `1080p`
- `1440p`
- `2160p`

Noise suppression values:

- `none`
- `deepfilternet`
- `rnnoise`
- `iris-carthy`
- `krisp-high`
- `krisp-medium`
- `krisp-low`
- `krisp-high-with-bvc`
- `krisp-medium-with-bvc`
- `ai-coustics-sparrow-xxs`
- `ai-coustics-sparrow-xs`
- `ai-coustics-sparrow-s`
- `ai-coustics-sparrow-l`
- `ai-coustics-sparrow-xxs-48khz`
- `ai-coustics-sparrow-xs-48khz`
- `ai-coustics-rook-s-48khz`
- `ai-coustics-rook-l-48khz`

Use an integer for `--video-max-concurrent-tracks` or JSON `video_max_concurrent_tracks`. In participant JSON, `null` is treated as absent and therefore inherits the global value; it does not clear a global track limit.

## Agent Workflow

1. Prefer `remote-stub` for a fast smoke test when browser automation is not the thing under test.
2. Use `local` for real Chromium-driven joining, and confirm the target Hyper frontend exposes the media settings used by video constraints.
3. Put common settings in global CLI flags, then use repeated `--participant` JSON for per-participant differences.
4. Keep JSON compact and quote it with single quotes in shell commands.
5. Check `cargo run -- headless --help` or `hyper-client-simulator headless --help` if the command rejects a flag.
4 changes: 4 additions & 0 deletions .codex/skills/run-headless-simulator/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
interface:
display_name: "Run Headless Simulator"
short_description: "Run simulator participants without the TUI"
default_prompt: "Use $run-headless-simulator to run hyper-client-simulator participants directly from the CLI with the headless command."
5 changes: 5 additions & 0 deletions .env.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# AWS device farm
DEVICE_FARM_AWS_ACCESS_KEY_ID={{ op://infra/aws-device-farm-simulator-credentials/access_key_id }}
DEVICE_FARM_AWS_SECRET_ACCESS_KEY={{ op://infra/aws-device-farm-simulator-credentials/secret_access_key }}
DEVICE_FARM_AWS_REGION=us-west-2
DEVICE_FARM_PROJECT_ARN={{ op://infra/aws-device-farm-simulator-credentials/mgpse2ej3msjproinokciv773m }}
2 changes: 2 additions & 0 deletions .envrc
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
export NIXPKGS_ALLOW_UNFREE=1 # for google-chrome
use flake . --impure

dotenv_if_exists .env
25 changes: 25 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ on:
pull_request:
branches: ['**']

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
Expand Down Expand Up @@ -41,14 +44,36 @@ jobs:
with:
token: ${{ secrets.GITHUB_TOKEN }}

private-submodule-notice:
name: Private Submodule Notice
runs-on: ubuntu-latest
timeout-minutes: 1
if: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name != github.repository }}

steps:
- name: Explain limited fork CI
run: |
echo "Full lint/test CI is skipped for fork pull requests because this public repository depends on the private hypervideo/cloudflare-browser-simulator submodule."
echo "Run the full workflow from a trusted branch after review."

lint-and-test:
name: Lint and Test
runs-on: ubuntu-latest
timeout-minutes: 10
if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
env:
DEVICE_FARM_AWS_ACCESS_KEY_ID: ${{ secrets.DEVICE_FARM_AWS_ACCESS_KEY_ID }}
DEVICE_FARM_AWS_SECRET_ACCESS_KEY: ${{ secrets.DEVICE_FARM_AWS_SECRET_ACCESS_KEY }}
DEVICE_FARM_AWS_REGION: ${{ secrets.DEVICE_FARM_AWS_REGION }}
DEVICE_FARM_PROJECT_ARN: ${{ secrets.DEVICE_FARM_PROJECT_ARN }}

steps:
- name: Checkout repository
uses: actions/checkout@v6.0.2
with:
persist-credentials: false
submodules: recursive
token: ${{ secrets.CLOUDFLARE_BROWSER_SIMULATOR_READ_TOKEN }}

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
Expand Down
13 changes: 13 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ jobs:
with:
persist-credentials: false
submodules: recursive
token: ${{ secrets.CLOUDFLARE_BROWSER_SIMULATOR_READ_TOKEN }}
- name: Install dist
# we specify bash to get pipefail; it guards against the `curl` command
# failing. otherwise `sh` won't catch that `curl` returned non-0
Expand Down Expand Up @@ -112,6 +113,10 @@ jobs:
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BUILD_MANIFEST_NAME: target/distrib/${{ join(matrix.targets, '-') }}-dist-manifest.json
DEVICE_FARM_AWS_ACCESS_KEY_ID: ${{ secrets.DEVICE_FARM_AWS_ACCESS_KEY_ID }}
DEVICE_FARM_AWS_SECRET_ACCESS_KEY: ${{ secrets.DEVICE_FARM_AWS_SECRET_ACCESS_KEY }}
DEVICE_FARM_AWS_REGION: ${{ secrets.DEVICE_FARM_AWS_REGION }}
DEVICE_FARM_PROJECT_ARN: ${{ secrets.DEVICE_FARM_PROJECT_ARN }}
steps:
- name: enable windows longpaths
run: |
Expand All @@ -120,6 +125,7 @@ jobs:
with:
persist-credentials: false
submodules: recursive
token: ${{ secrets.CLOUDFLARE_BROWSER_SIMULATOR_READ_TOKEN }}
- name: Install Rust non-interactively if not already installed
if: ${{ matrix.container }}
run: |
Expand Down Expand Up @@ -174,11 +180,16 @@ jobs:
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BUILD_MANIFEST_NAME: target/distrib/global-dist-manifest.json
DEVICE_FARM_AWS_ACCESS_KEY_ID: ${{ secrets.DEVICE_FARM_AWS_ACCESS_KEY_ID }}
DEVICE_FARM_AWS_SECRET_ACCESS_KEY: ${{ secrets.DEVICE_FARM_AWS_SECRET_ACCESS_KEY }}
DEVICE_FARM_AWS_REGION: ${{ secrets.DEVICE_FARM_AWS_REGION }}
DEVICE_FARM_PROJECT_ARN: ${{ secrets.DEVICE_FARM_PROJECT_ARN }}
steps:
- uses: actions/checkout@v6
with:
persist-credentials: false
submodules: recursive
token: ${{ secrets.CLOUDFLARE_BROWSER_SIMULATOR_READ_TOKEN }}
- name: Install cached dist
uses: actions/download-artifact@v7
with:
Expand Down Expand Up @@ -229,6 +240,7 @@ jobs:
with:
persist-credentials: false
submodules: recursive
token: ${{ secrets.CLOUDFLARE_BROWSER_SIMULATOR_READ_TOKEN }}
- name: Install cached dist
uses: actions/download-artifact@v7
with:
Expand Down Expand Up @@ -341,3 +353,4 @@ jobs:
with:
persist-credentials: false
submodules: recursive
token: ${{ secrets.CLOUDFLARE_BROWSER_SIMULATOR_READ_TOKEN }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ target/
tmp/
hyper_session_cookies.json
/.direnv/
/.env
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "cloudflare-browser-simulator"]
path = cloudflare-browser-simulator
url = https://github.com/hypervideo/cloudflare-browser-simulator.git
Loading
Loading