Skip to content

Latest commit

History

72 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

browsertools

browsertools is OpenUdon's tooling project for turning real website UI evidence into reviewed UWS browser capability profiles.

It exists for the gap where a task is exposed through a web UI and no suitable API source document is available. The output is not a browser command trace and not an OpenAPI substitute. The output is a portable, reviewed browser-profile document that a UWS workflow can bind to.

real website UI
-> browsertools using Playwright / llm-scraper / Crawl4AI / Firecrawl
-> reviewed browser-profile
-> UWS operation binds to browser-profile action

Where Browsertools Fits

OpenUdon's iCoT is the primary end-user authoring entry point across API, browser, and runtime-handoff sources. iCoT retains goal interviewing, LLM/human interaction, source selection, and package staging. For UI-only acquisition, the distributed icot executable re-executes a private copy of itself as a separate process using Browsertools' importable worker; an external browsertools CLI remains available for experts and maintainers.

Browsertools owns Playwright-based acquisition, browser safety policy, profile synthesis, and the shared validation library for browser capability and authentication profiles, plus offline validation/draft/review tooling for the separate UWS browser-registration profile. Its CLI is primarily a machine- facing protocol plus maintainer and offline tooling, not a parallel end-user authoring product. Browsertools is not the production runtime; runtime replay belongs to Udon and Browserdriver. See the canonical OpenUdon integration reference for the two integration paths and full ownership split.

For UWS 1.9.1 advisory integrity analysis, package github.com/OpenUdon/browsertools/contenttrust builds a resolver from reviewed profiles keyed by sourceDescription name. Browser-derived outputs default to untrusted while retaining their declared value shape. Navigation and option selection parameters are authority-bearing, confirmation prompts are instructions, and typed text remains data. The resolver performs no browser work and never changes validation or execution.

Authenticated live authoring uses the strict browsertools.author-session.v2 NDJSON boundary. Human-reviewed MFA kinds and up to 16 final accessibility outputs produce one private browsertools.authenticated-authoring.v2 envelope; the protocol carries no credential, page value, cookie, or browser state. See Authenticated goal-directed browser authoring.

Registration authoring has separate browser-independent contracts. V1 (browsertools.registration-author-session.v1 and private browsertools.registration-authoring.v1) remains query-free. Additive v2 (browsertools.registration-author-session.v2 and private browsertools.registration-authoring.v2) admits only bounded canonical literal structural queries and validates them on all session and retained BRP navigations. Both continue only approved-origin GET/HEAD traffic and bind one reviewed inert BRP without claiming a submit, account attempt, session, or supported runtime. Canonical unapproved non-navigation GET/HEAD subresources are counted and aborted before contact without expanding the allowlist or poisoning an otherwise clean observation; unsafe navigation, methods, and persistent channels remain fatal. A guarded typed Chromium backend and deterministic explicit candidate builder implement those contracts. The importable registrationauthorworker and browsertools registration-author-session chromium expose that backend through the same closed no-submit wire and finalize the result only under an explicit owner-only private root. See Browser registration profiles.

Page-controlled frame names cross the same canonical reduction boundary as candidate labels. Exact backend-reported MFA subsets are preserved, and the finite total timeout charges browser work rather than human credential/MFA wait time.

The authorworker package is the supported process-entry adapter for browsertools author-session chromium and the hidden iCoT worker. It accepts context, private root, optional driver directory, interruptible owned stdin, and stdout. SIGINT/SIGTERM or parent cancellation closes protocol input, then waits for browser teardown; failed close negotiation or teardown exits nonzero. Embedding it does not move Playwright into the iCoT engine or HTTP server process.

The separate registrationauthorworker is the supported process entry for no-submit BRP production. It performs read-only pinned-driver preflight, owns the closeable NDJSON input and headed browser lifetime, and creates an independently reconstructed result only after clean teardown. Its API and CLI return no result path or digest. A re-executing parent owns executable hashing, minimal child environment, and process-group termination. On Linux, an administrator-provisioned CHROME_DEVEL_SANDBOX is forwarded to Chromium only after exact mode, root ownership, link count, setuid-filesystem, resolved-path, and complete ancestor-control checks; sandbox disabling is never supported.

Accessibility-label reduction is a useful heuristic, not data loss prevention. Ordinary names, identifiers, and order numbers can remain in reduced observations and reviewed traces. Operators must review those records before retaining or sharing them.

Quick Start

go get github.com/OpenUdon/browsertools

The full pipeline from evidence to a reviewable bundle:

import (
"time""github.com/OpenUdon/browsertools/adapter""github.com/OpenUdon/browsertools/adapter/playwright""github.com/OpenUdon/browsertools/bundle""github.com/OpenUdon/browsertools/draft""github.com/OpenUdon/browsertools/evidence""github.com/OpenUdon/browsertools/profile""github.com/OpenUdon/browsertools/review"
)
// 1. Import saved Playwright snapshot as normalized evidence.a:=&playwright.Adapter{}
records, err:=a.Import(snapshotJSON, adapter.Options{
Origin: "https://example.test",
ActionHint: "read_status",
RedactionStatus: evidence.RedactionNotRequired,
})
// 2. Add explicit action intent. Evidence never invents a click or assumes// that an action is read-only.result, err:=draft.Build(records, draft.Spec{
Info: profile.Info{Title: "Example", Origin: profile.Origins{"https://example.test"}},
ObservationKind: profile.ObservationAccessibilitySnapshot,
Confidence: profile.ConfidenceMedium,
ExpiresAfter: "P30D",
Actions: map[string]draft.ActionSpec{
"read_status": {
Sequence: []profile.Step{
{Kind: profile.StepNavigate, Navigate: "/status"},
{Kind: profile.StepWaitFor, WaitFor: &profile.WaitForCondition{
Locator: &profile.Locator{Role: profile.RoleStatus, Name: "OK"},
}},
},
SideEffects: []profile.SideEffect{profile.SideEffectReadOnly},
ConfirmationPolicy: profile.ConfirmationPolicy{Required: false},
},
},
})
// 3. Build a digest-bound bundle at an explicit assessment time.assessedAt:=time.Now().UTC()
reviewed, err:=review.Build(result.Profile, records, result.Decisions, assessedAt)
iferr!=nil||!reviewed.Promotable() {
// fix gaps before promoting
}
// 4. Wrap the exact reviewed inputs in an inert publication bundle.published, err:=bundle.Build(bundle.BuildOptions{
ID: "example/status", Release: "1.0.0", Source: "reviewed_fixture",
License: "CC0-1.0", Profile: result.Profile, Review: reviewed,
Evidence: records, PublishedAt: assessedAt,
})

The CLI exposes the same offline pipeline:

go run ./cmd/browsertools profile validate --input ./profiles/example.yaml
go run ./cmd/browsertools evidence import \
--adapter playwright --input ./capture.json \
--origin https://example.test --redaction-status not_required \
--out ./evidence.json
go run ./cmd/browsertools draft build \
--evidence ./evidence.json --spec ./draft-spec.yaml \
--out ./profile.yaml
go run ./cmd/browsertools review bundle \
--profile ./profile.yaml --evidence ./evidence.json \
--at 2026-08-14T00:00:00Z --out ./review-bundle.json
go run ./cmd/browsertools revalidate check \
--profile ./profile.yaml --evidence ./evidence.json \
--at 2026-08-14T00:00:00Z --out ./revalidation.json
go run ./cmd/browsertools bundle build \
--id example/status --release 1.0.0 \
--profile ./profile.yaml --review ./review-bundle.json \
--evidence ./evidence.json --source reviewed_fixture --license CC0-1.0 \
--published-at 2026-08-14T00:00:00Z --out ./capability-bundle.json
go run ./cmd/browsertools bundle verify \
--input ./capability-bundle.json --at 2026-08-14T00:00:00Z
go run ./cmd/browsertools registry publish \
--root ./public-registry --bundle ./capability-bundle.json \
--at 2026-08-14T00:00:00Z
go run ./cmd/browsertools registry search \
--location ./public-registry --query status \
--at 2026-08-14T00:00:00Z

Browser acquisition is an explicit, separately installed authoring feature. Browsertools pins Playwright-Go v0.6201.0 (Playwright 1.62.1). Install the matching driver and Chromium deliberately, then verify the local installation:

go run github.com/mxschmitt/playwright-go/cmd/playwright@v0.6201.0 install chromium
go run ./cmd/browsertools playwright doctor --engine chromium

Before playwright doctor or an author session starts, Browsertools verifies the installed Node executable, CLI, and exact Playwright 1.62.1 package using read-only filesystem checks. It creates no cache directory, invokes no installer, and contacts no network. The doctor then starts and stops only that installed driver; its full local CLI report may include the browser executable path, while the separate UI-safe report omits executable and private paths. It does not contact a site or launch a browser. The other CLI commands remain file-first unless they are explicitly named live acquisition, check, or assisted-authentication commands.

Safe live capture is Chromium-only, headless, non-interactive, and private. It requires every exact origin and writes page material only to a finite-retention private_raw cache entry:

go run ./cmd/browsertools capture chromium \
--url https://example.test/member \
--allow-origin https://example.test \
--cache-root ./.browsertools-cache \
--action-hint read_dashboard \
--retain-for 24h

The command blocks non-GET/HEAD requests, unapproved origins, child frames, service workers, WebSockets, popups, downloads, dialogs, file choosers, and non-essential resources. It uses finite navigation, total, request, response, ARIA-depth, evidence-size, and retention limits. Only cache metadata is printed; raw ARIA/JSON-LD content is never written to stdout. See Safe live capture for the review/redaction handoff.

Explicit private screenshots, traces, and minimal-content HAR can be captured as one short-lived, non-publishable ZIP:

go run ./cmd/browsertools rich-capture chromium \
--url https://example.test/member \
--allow-origin https://example.test \
--cache-root ./.browsertools-cache \
--artifact screenshot --artifact trace --artifact har \
--retain-for 1h

The command prints only cache metadata. Export requires a new 0600 file; review for secrets is mandatory, and cache delete requires the exact digest twice. Rich artifacts have no publication or normalized-evidence path.

After normalization, the terminal guide makes every capability and safety decision explicit and emits one deterministic envelope containing the accepted spec, generated profile, action-bound evidence, ambiguity decisions, and promotable review:

go run ./cmd/browsertools guide author \
--evidence ./evidence.json \
--at 2026-08-16T12:00:00Z \
--out ./guided-authoring.json

A separately selected live check can compare declared locators, waits, and output shapes with the current page without executing any profile macro or emitting page values:

go run ./cmd/browsertools live-check chromium \
--profile ./profile.yaml \
--url https://example.test/member \
--allow-origin https://example.test \
--action read_dashboard \
--at 2026-08-16T12:00:00Z \
--out ./live-check.json

Both paths keep sequence intent, side effects, confirmation, expiry, and ambiguity decisions human-authored. The live check reuses the exact-origin ephemeral capture policy, accepts plain CSS outputs but no Playwright selector language, and writes only profile-bound match/type facts. See Guided capability authoring and live checks.

The same profile-derived read-only checks can be compared without locator rewrites across explicitly installed engines:

go run ./cmd/browsertools portability check \
--profile ./profile.yaml \
--url https://example.test/member \
--allow-origin https://example.test \
--action read_dashboard \
--engine chromium --engine firefox --engine webkit \
--out ./portability.json

Chromium is the required baseline. Missing engines and shape differences are fixed value-free diagnostics, not silent fallbacks. See Private rich evidence and cross-engine portability.

Portable sign-in recipes use a separate additive contract and remain local to the workflow package:

go run ./cmd/browsertools auth-draft build \
--spec ./authentication-spec.yaml \
--out ./browser-authentication/member.yaml
go run ./cmd/browsertools auth-profile validate \
--input ./browser-authentication/member.yaml \
--at 2026-08-16T00:00:00Z
go run ./cmd/browsertools auth-review bundle \
--profile ./browser-authentication/member.yaml \
--at 2026-08-16T00:00:00Z \
--out ./browser-authentication/member.review.json

An explicit headed authoring command can then observe the exact recipe while the operator enters credentials and completes MFA directly in the browser:

go run ./cmd/browsertools auth-assist chromium \
--profile ./browser-authentication/member.yaml \
--flow member_login_push \
--approve-origin https://members.example.test \
--approve-origin https://login.example.test \
--post-budget member_login_push:3=2 \
--out ./browser-authentication/member.assisted.json

The profile supplies every locator, challenge alternative, submit step, and success condition; Browsertools does not infer them. Each selected flow runs in a separate visible ephemeral context. Browsertools navigates declared URLs and counts declared accessibility locators, but the operator performs every credential, click, and challenge step and signals completion with an empty terminal line. A POST is blocked unless its exact zero-based flow step has an explicit bounded --post-budget; all other mutating methods are blocked.

The 0600 output is created only after every context has closed and contains a selected uws.browser-authentication.1.0 profile, its digest-bound review, and value-free origin/count/request evidence. It cannot use stdin for a profile, stdout for the artifact, or overwrite a path. Authentication recipes are also excluded from static registry publication. Actual credentials, MFA responses, OAuth state, cookies, storage, and sessions stay in the browser or downstream private runtime. See Browser authentication profiles.

Account registration uses a separate explicitly mutating contract. Browsertools can validate, deterministically build, and digest-review only the inert recipe:

go run ./cmd/browsertools registration-draft build \
--spec ./registration-spec.yaml \
--out ./browser-registration/dedicated-test-user.yaml
go run ./cmd/browsertools registration-profile validate \
--input ./browser-registration/dedicated-test-user.yaml \
--at 2026-08-25T00:00:00Z
go run ./cmd/browsertools registration-review bundle \
--profile ./browser-registration/dedicated-test-user.yaml \
--at 2026-08-25T00:00:00Z \
--out ./browser-registration/dedicated-test-user.review.json

These commands are file-only and never launch a browser, contact a target, resolve a symbolic credential, submit a registration, handle CAPTCHA/MFA/email verification, approve a run, or perform cleanup. Registration profiles and reviews remain package-local and are excluded from the browser capability registry. See Browser registration profiles.

The typed registrationauthor.Build path combines one current reduced registration observation with a complete registrationdraft.Spec, exact reviewed candidate IDs, selected submit candidate and flow, approved origins, and explicit fixed call controls. It reconstructs the current-generation candidate IDs, binds the one accessibility-name submit, and emits the exact M26 review message without inferring any profile or cleanup field. After clean session teardown, registrationauthorresult.FinalizePrivate independently reconstructs and strict-decodes the M26 result before and after an anchored owner-only, create-once write; its path remains process-private.

The standalone producer uses that complete path:

browsertools registration-author-session chromium \
--private-root ./private-registration-results \
--driver-dir "$PLAYWRIGHT_DRIVER_PATH"

Stdin and stdout are reserved for registration author-session NDJSON. The worker defaults to v1; --protocol v2 deliberately selects the additive retained-query contract and guarded Chromium routing. The private root must already be a mode-0700 directory. The command never prints the resulting file name or digest, and it provides no registration runtime or submit command.

Caller-supplied raw captures and derived artifacts can be kept in an explicit private local cache. Raw entries can never be publication eligible:

go run ./cmd/browsertools cache put \
--root ./.browsertools-cache --input ./capture.json \
--kind private_raw --media-type application/json \
--created-at 2026-08-14T00:00:00Z
go run ./cmd/browsertools cache list \
--root ./.browsertools-cache --at 2026-08-14T12:00:00Z
go run ./cmd/browsertools cache prune \
--root ./.browsertools-cache --at 2026-09-14T00:00:00Z
go run ./cmd/browsertools cache delete \
--root ./.browsertools-cache --id sha256:EXACT_ID --confirm-id sha256:EXACT_ID

What It Owns

  • A complete typed model and validation helpers for UWS browser-profile documents.
  • Typed validation, deterministic drafting, digest-bound review, freshness, and local discovery for package-local uws.browser-authentication.1.0 recipes.
  • Typed offline validation, deterministic explicit drafting, digest-bound review, and freshness for package-local uws.browser-registration.1.0 recipes.
  • Secret-free evidence records from browser and scraper tooling.
  • Draft profile generation from reviewed evidence.
  • Review bundles with validation, confidence, expiry, side-effect, and revalidation notes.
  • Deterministic fixture-only revalidation and digest-bound promotion gates.
  • A bounded, content-addressed private cache for caller-supplied experiences, normalized evidence, profiles, and review bundles.
  • Canonical, digest-bound, lifecycle-assessed publication bundles for reviewed profiles, safe evidence, and optional inert UWS companions.
  • A service-free static registry layout, atomic local publisher, bounded local/HTTPS reader, and local browser-source discovery report.
  • Browser-profile, scraper/crawler, and browser-backed wrapper examples.
  • Optional adapters for Playwright, llm-scraper, Crawl4AI, and Firecrawl outputs.
  • An isolated Playwright-Go acquisition boundary, pinned capability policy, and offline installation doctor for authoring-only browser tooling.
  • Explicit headless Chromium acquisition into the private raw cache with exact origins, ephemeral context destruction, and closed activity/resource bounds.
  • Deterministic terminal-guided authoring that binds explicit intent, reviewed evidence, decisions, a valid profile, and a promotable review.
  • Value-free Chromium live checks for declared locators, waits, and output shapes without macro execution.
  • Explicit short-lived screenshot/trace/HAR bundles with mandatory secret review, no publication path, and exact-ID deletion.
  • Fresh Chromium-baseline Firefox/WebKit comparisons of the same value-free profile probes, plus documented browser.1.6 contract pressure.
  • Headed manual authentication observation with separate ephemeral contexts, exact preapproved origins, step-scoped POST ceilings, and local value-free draft/review bundles.

What It Does Not Own

  • UWS schema and workflow semantics. Those live in github.com/OpenUdon/uws.
  • OpenAPI/API-source discovery and provider catalog metadata. Those belong in github.com/OpenUdon/apitools.
  • Production browser execution, runtime credential resolution, retained cookies/sessions, retries, account selection, or production side effects.
  • A general Playwright, WebDriver, Puppeteer, or scraping DSL.
  • Implicit browser launch or uploading cached content. Acquisition commands are separately selected; cache commands are local and offline, and publication has a separate verification boundary.
  • Accounts, membership, a registry database, remote writes, or deployment credentials. Static catalogs are reviewed and deployed by existing repository/hosting workflows.
  • Publication of authentication recipes through the static browser capability registry.
  • Publication of registration recipes through the static browser capability registry, or live registration/account cleanup of any kind.

Why Not Just OpenAPI?

OpenAPI should describe a stable HTTP service. If you build a browser-backed wrapper service, OpenAPI should describe that wrapper. Browsertools can also emit an advisory overlay sidecar for the wrapper, linking OpenAPI operations to reviewed browser-profile actions and review bundles.

browser-profile describes the UI binding behind the wrapper or behind a UWS browser operation:

website UI
-> browsertools-reviewed profile
-> browser runtime executes profile

or:

website UI
-> browser-backed wrapper service
-> OpenAPI describes wrapper
-> UWS binds to wrapper API

Documentation

Development

go test ./...
go vet ./...
GOWORK=off go run golang.org/x/vuln/cmd/govulncheck@v1.6.0 ./...
git diff --check
(cd ../uws && go test ./...)

Default tests use fakes and synthetic fixtures; they do not install or launch browsers and do not contact the network.

An installed-browser loopback integration test is opt-in:

BROWSERTOOLS_LIVE_TEST=1 go test ./capture -run PlaywrightLiveCaptureLoopback

Headed authentication behavior is covered by browser-free policy/state-machine tests by default. A real site is never contacted by the test suite. An installed-browser headed smoke test is separately opt-in and loopback-only:

BROWSERTOOLS_AUTH_LIVE_TEST=1 go test ./capture -run PlaywrightAuthHeadedLoopback

Rich evidence and cross-engine smoke tests are independently gated and remain loopback-only:

BROWSERTOOLS_RICH_LIVE_TEST=1 go test ./capture -run PlaywrightRichCaptureLoopback
BROWSERTOOLS_PORTABILITY_LIVE_TEST=1 go test ./capture -run PlaywrightPortabilityLoopback

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
GitHub - OpenUdon/browsertools · GitHub
Skip to content

Latest commit

History

72 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

browsertools

browsertools is OpenUdon's tooling project for turning real website UI evidence into reviewed UWS browser capability profiles.

It exists for the gap where a task is exposed through a web UI and no suitable API source document is available. The output is not a browser command trace and not an OpenAPI substitute. The output is a portable, reviewed browser-profile document that a UWS workflow can bind to.

real website UI
-> browsertools using Playwright / llm-scraper / Crawl4AI / Firecrawl
-> reviewed browser-profile
-> UWS operation binds to browser-profile action

Where Browsertools Fits

OpenUdon's iCoT is the primary end-user authoring entry point across API, browser, and runtime-handoff sources. iCoT retains goal interviewing, LLM/human interaction, source selection, and package staging. For UI-only acquisition, the distributed icot executable re-executes a private copy of itself as a separate process using Browsertools' importable worker; an external browsertools CLI remains available for experts and maintainers.

Browsertools owns Playwright-based acquisition, browser safety policy, profile synthesis, and the shared validation library for browser capability and authentication profiles, plus offline validation/draft/review tooling for the separate UWS browser-registration profile. Its CLI is primarily a machine- facing protocol plus maintainer and offline tooling, not a parallel end-user authoring product. Browsertools is not the production runtime; runtime replay belongs to Udon and Browserdriver. See the canonical OpenUdon integration reference for the two integration paths and full ownership split.

For UWS 1.9.1 advisory integrity analysis, package github.com/OpenUdon/browsertools/contenttrust builds a resolver from reviewed profiles keyed by sourceDescription name. Browser-derived outputs default to untrusted while retaining their declared value shape. Navigation and option selection parameters are authority-bearing, confirmation prompts are instructions, and typed text remains data. The resolver performs no browser work and never changes validation or execution.

Authenticated live authoring uses the strict browsertools.author-session.v2 NDJSON boundary. Human-reviewed MFA kinds and up to 16 final accessibility outputs produce one private browsertools.authenticated-authoring.v2 envelope; the protocol carries no credential, page value, cookie, or browser state. See Authenticated goal-directed browser authoring.

Registration authoring has separate browser-independent contracts. V1 (browsertools.registration-author-session.v1 and private browsertools.registration-authoring.v1) remains query-free. Additive v2 (browsertools.registration-author-session.v2 and private browsertools.registration-authoring.v2) admits only bounded canonical literal structural queries and validates them on all session and retained BRP navigations. Both continue only approved-origin GET/HEAD traffic and bind one reviewed inert BRP without claiming a submit, account attempt, session, or supported runtime. Canonical unapproved non-navigation GET/HEAD subresources are counted and aborted before contact without expanding the allowlist or poisoning an otherwise clean observation; unsafe navigation, methods, and persistent channels remain fatal. A guarded typed Chromium backend and deterministic explicit candidate builder implement those contracts. The importable registrationauthorworker and browsertools registration-author-session chromium expose that backend through the same closed no-submit wire and finalize the result only under an explicit owner-only private root. See Browser registration profiles.

Page-controlled frame names cross the same canonical reduction boundary as candidate labels. Exact backend-reported MFA subsets are preserved, and the finite total timeout charges browser work rather than human credential/MFA wait time.

The authorworker package is the supported process-entry adapter for browsertools author-session chromium and the hidden iCoT worker. It accepts context, private root, optional driver directory, interruptible owned stdin, and stdout. SIGINT/SIGTERM or parent cancellation closes protocol input, then waits for browser teardown; failed close negotiation or teardown exits nonzero. Embedding it does not move Playwright into the iCoT engine or HTTP server process.

The separate registrationauthorworker is the supported process entry for no-submit BRP production. It performs read-only pinned-driver preflight, owns the closeable NDJSON input and headed browser lifetime, and creates an independently reconstructed result only after clean teardown. Its API and CLI return no result path or digest. A re-executing parent owns executable hashing, minimal child environment, and process-group termination. On Linux, an administrator-provisioned CHROME_DEVEL_SANDBOX is forwarded to Chromium only after exact mode, root ownership, link count, setuid-filesystem, resolved-path, and complete ancestor-control checks; sandbox disabling is never supported.

Accessibility-label reduction is a useful heuristic, not data loss prevention. Ordinary names, identifiers, and order numbers can remain in reduced observations and reviewed traces. Operators must review those records before retaining or sharing them.

Quick Start

go get github.com/OpenUdon/browsertools

The full pipeline from evidence to a reviewable bundle:

import (
"time""github.com/OpenUdon/browsertools/adapter""github.com/OpenUdon/browsertools/adapter/playwright""github.com/OpenUdon/browsertools/bundle""github.com/OpenUdon/browsertools/draft""github.com/OpenUdon/browsertools/evidence""github.com/OpenUdon/browsertools/profile""github.com/OpenUdon/browsertools/review"
)
// 1. Import saved Playwright snapshot as normalized evidence.a:=&playwright.Adapter{}
records, err:=a.Import(snapshotJSON, adapter.Options{
Origin: "https://example.test",
ActionHint: "read_status",
RedactionStatus: evidence.RedactionNotRequired,
})
// 2. Add explicit action intent. Evidence never invents a click or assumes// that an action is read-only.result, err:=draft.Build(records, draft.Spec{
Info: profile.Info{Title: "Example", Origin: profile.Origins{"https://example.test"}},
ObservationKind: profile.ObservationAccessibilitySnapshot,
Confidence: profile.ConfidenceMedium,
ExpiresAfter: "P30D",
Actions: map[string]draft.ActionSpec{
"read_status": {
Sequence: []profile.Step{
{Kind: profile.StepNavigate, Navigate: "/status"},
{Kind: profile.StepWaitFor, WaitFor: &profile.WaitForCondition{
Locator: &profile.Locator{Role: profile.RoleStatus, Name: "OK"},
}},
},
SideEffects: []profile.SideEffect{profile.SideEffectReadOnly},
ConfirmationPolicy: profile.ConfirmationPolicy{Required: false},
},
},
})
// 3. Build a digest-bound bundle at an explicit assessment time.assessedAt:=time.Now().UTC()
reviewed, err:=review.Build(result.Profile, records, result.Decisions, assessedAt)
iferr!=nil||!reviewed.Promotable() {
// fix gaps before promoting
}
// 4. Wrap the exact reviewed inputs in an inert publication bundle.published, err:=bundle.Build(bundle.BuildOptions{
ID: "example/status", Release: "1.0.0", Source: "reviewed_fixture",
License: "CC0-1.0", Profile: result.Profile, Review: reviewed,
Evidence: records, PublishedAt: assessedAt,
})

The CLI exposes the same offline pipeline:

go run ./cmd/browsertools profile validate --input ./profiles/example.yaml
go run ./cmd/browsertools evidence import \
--adapter playwright --input ./capture.json \
--origin https://example.test --redaction-status not_required \
--out ./evidence.json
go run ./cmd/browsertools draft build \
--evidence ./evidence.json --spec ./draft-spec.yaml \
--out ./profile.yaml
go run ./cmd/browsertools review bundle \
--profile ./profile.yaml --evidence ./evidence.json \
--at 2026-08-14T00:00:00Z --out ./review-bundle.json
go run ./cmd/browsertools revalidate check \
--profile ./profile.yaml --evidence ./evidence.json \
--at 2026-08-14T00:00:00Z --out ./revalidation.json
go run ./cmd/browsertools bundle build \
--id example/status --release 1.0.0 \
--profile ./profile.yaml --review ./review-bundle.json \
--evidence ./evidence.json --source reviewed_fixture --license CC0-1.0 \
--published-at 2026-08-14T00:00:00Z --out ./capability-bundle.json
go run ./cmd/browsertools bundle verify \
--input ./capability-bundle.json --at 2026-08-14T00:00:00Z
go run ./cmd/browsertools registry publish \
--root ./public-registry --bundle ./capability-bundle.json \
--at 2026-08-14T00:00:00Z
go run ./cmd/browsertools registry search \
--location ./public-registry --query status \
--at 2026-08-14T00:00:00Z

Browser acquisition is an explicit, separately installed authoring feature. Browsertools pins Playwright-Go v0.6201.0 (Playwright 1.62.1). Install the matching driver and Chromium deliberately, then verify the local installation:

go run github.com/mxschmitt/playwright-go/cmd/playwright@v0.6201.0 install chromium
go run ./cmd/browsertools playwright doctor --engine chromium

Before playwright doctor or an author session starts, Browsertools verifies the installed Node executable, CLI, and exact Playwright 1.62.1 package using read-only filesystem checks. It creates no cache directory, invokes no installer, and contacts no network. The doctor then starts and stops only that installed driver; its full local CLI report may include the browser executable path, while the separate UI-safe report omits executable and private paths. It does not contact a site or launch a browser. The other CLI commands remain file-first unless they are explicitly named live acquisition, check, or assisted-authentication commands.

Safe live capture is Chromium-only, headless, non-interactive, and private. It requires every exact origin and writes page material only to a finite-retention private_raw cache entry:

go run ./cmd/browsertools capture chromium \
--url https://example.test/member \
--allow-origin https://example.test \
--cache-root ./.browsertools-cache \
--action-hint read_dashboard \
--retain-for 24h

The command blocks non-GET/HEAD requests, unapproved origins, child frames, service workers, WebSockets, popups, downloads, dialogs, file choosers, and non-essential resources. It uses finite navigation, total, request, response, ARIA-depth, evidence-size, and retention limits. Only cache metadata is printed; raw ARIA/JSON-LD content is never written to stdout. See Safe live capture for the review/redaction handoff.

Explicit private screenshots, traces, and minimal-content HAR can be captured as one short-lived, non-publishable ZIP:

go run ./cmd/browsertools rich-capture chromium \
--url https://example.test/member \
--allow-origin https://example.test \
--cache-root ./.browsertools-cache \
--artifact screenshot --artifact trace --artifact har \
--retain-for 1h

The command prints only cache metadata. Export requires a new 0600 file; review for secrets is mandatory, and cache delete requires the exact digest twice. Rich artifacts have no publication or normalized-evidence path.

After normalization, the terminal guide makes every capability and safety decision explicit and emits one deterministic envelope containing the accepted spec, generated profile, action-bound evidence, ambiguity decisions, and promotable review:

go run ./cmd/browsertools guide author \
--evidence ./evidence.json \
--at 2026-08-16T12:00:00Z \
--out ./guided-authoring.json

A separately selected live check can compare declared locators, waits, and output shapes with the current page without executing any profile macro or emitting page values:

go run ./cmd/browsertools live-check chromium \
--profile ./profile.yaml \
--url https://example.test/member \
--allow-origin https://example.test \
--action read_dashboard \
--at 2026-08-16T12:00:00Z \
--out ./live-check.json

Both paths keep sequence intent, side effects, confirmation, expiry, and ambiguity decisions human-authored. The live check reuses the exact-origin ephemeral capture policy, accepts plain CSS outputs but no Playwright selector language, and writes only profile-bound match/type facts. See Guided capability authoring and live checks.

The same profile-derived read-only checks can be compared without locator rewrites across explicitly installed engines:

go run ./cmd/browsertools portability check \
--profile ./profile.yaml \
--url https://example.test/member \
--allow-origin https://example.test \
--action read_dashboard \
--engine chromium --engine firefox --engine webkit \
--out ./portability.json

Chromium is the required baseline. Missing engines and shape differences are fixed value-free diagnostics, not silent fallbacks. See Private rich evidence and cross-engine portability.

Portable sign-in recipes use a separate additive contract and remain local to the workflow package:

go run ./cmd/browsertools auth-draft build \
--spec ./authentication-spec.yaml \
--out ./browser-authentication/member.yaml
go run ./cmd/browsertools auth-profile validate \
--input ./browser-authentication/member.yaml \
--at 2026-08-16T00:00:00Z
go run ./cmd/browsertools auth-review bundle \
--profile ./browser-authentication/member.yaml \
--at 2026-08-16T00:00:00Z \
--out ./browser-authentication/member.review.json

An explicit headed authoring command can then observe the exact recipe while the operator enters credentials and completes MFA directly in the browser:

go run ./cmd/browsertools auth-assist chromium \
--profile ./browser-authentication/member.yaml \
--flow member_login_push \
--approve-origin https://members.example.test \
--approve-origin https://login.example.test \
--post-budget member_login_push:3=2 \
--out ./browser-authentication/member.assisted.json

The profile supplies every locator, challenge alternative, submit step, and success condition; Browsertools does not infer them. Each selected flow runs in a separate visible ephemeral context. Browsertools navigates declared URLs and counts declared accessibility locators, but the operator performs every credential, click, and challenge step and signals completion with an empty terminal line. A POST is blocked unless its exact zero-based flow step has an explicit bounded --post-budget; all other mutating methods are blocked.

The 0600 output is created only after every context has closed and contains a selected uws.browser-authentication.1.0 profile, its digest-bound review, and value-free origin/count/request evidence. It cannot use stdin for a profile, stdout for the artifact, or overwrite a path. Authentication recipes are also excluded from static registry publication. Actual credentials, MFA responses, OAuth state, cookies, storage, and sessions stay in the browser or downstream private runtime. See Browser authentication profiles.

Account registration uses a separate explicitly mutating contract. Browsertools can validate, deterministically build, and digest-review only the inert recipe:

go run ./cmd/browsertools registration-draft build \
--spec ./registration-spec.yaml \
--out ./browser-registration/dedicated-test-user.yaml
go run ./cmd/browsertools registration-profile validate \
--input ./browser-registration/dedicated-test-user.yaml \
--at 2026-08-25T00:00:00Z
go run ./cmd/browsertools registration-review bundle \
--profile ./browser-registration/dedicated-test-user.yaml \
--at 2026-08-25T00:00:00Z \
--out ./browser-registration/dedicated-test-user.review.json

These commands are file-only and never launch a browser, contact a target, resolve a symbolic credential, submit a registration, handle CAPTCHA/MFA/email verification, approve a run, or perform cleanup. Registration profiles and reviews remain package-local and are excluded from the browser capability registry. See Browser registration profiles.

The typed registrationauthor.Build path combines one current reduced registration observation with a complete registrationdraft.Spec, exact reviewed candidate IDs, selected submit candidate and flow, approved origins, and explicit fixed call controls. It reconstructs the current-generation candidate IDs, binds the one accessibility-name submit, and emits the exact M26 review message without inferring any profile or cleanup field. After clean session teardown, registrationauthorresult.FinalizePrivate independently reconstructs and strict-decodes the M26 result before and after an anchored owner-only, create-once write; its path remains process-private.

The standalone producer uses that complete path:

browsertools registration-author-session chromium \
--private-root ./private-registration-results \
--driver-dir "$PLAYWRIGHT_DRIVER_PATH"

Stdin and stdout are reserved for registration author-session NDJSON. The worker defaults to v1; --protocol v2 deliberately selects the additive retained-query contract and guarded Chromium routing. The private root must already be a mode-0700 directory. The command never prints the resulting file name or digest, and it provides no registration runtime or submit command.

Caller-supplied raw captures and derived artifacts can be kept in an explicit private local cache. Raw entries can never be publication eligible:

go run ./cmd/browsertools cache put \
--root ./.browsertools-cache --input ./capture.json \
--kind private_raw --media-type application/json \
--created-at 2026-08-14T00:00:00Z
go run ./cmd/browsertools cache list \
--root ./.browsertools-cache --at 2026-08-14T12:00:00Z
go run ./cmd/browsertools cache prune \
--root ./.browsertools-cache --at 2026-09-14T00:00:00Z
go run ./cmd/browsertools cache delete \
--root ./.browsertools-cache --id sha256:EXACT_ID --confirm-id sha256:EXACT_ID

What It Owns

  • A complete typed model and validation helpers for UWS browser-profile documents.
  • Typed validation, deterministic drafting, digest-bound review, freshness, and local discovery for package-local uws.browser-authentication.1.0 recipes.
  • Typed offline validation, deterministic explicit drafting, digest-bound review, and freshness for package-local uws.browser-registration.1.0 recipes.
  • Secret-free evidence records from browser and scraper tooling.
  • Draft profile generation from reviewed evidence.
  • Review bundles with validation, confidence, expiry, side-effect, and revalidation notes.
  • Deterministic fixture-only revalidation and digest-bound promotion gates.
  • A bounded, content-addressed private cache for caller-supplied experiences, normalized evidence, profiles, and review bundles.
  • Canonical, digest-bound, lifecycle-assessed publication bundles for reviewed profiles, safe evidence, and optional inert UWS companions.
  • A service-free static registry layout, atomic local publisher, bounded local/HTTPS reader, and local browser-source discovery report.
  • Browser-profile, scraper/crawler, and browser-backed wrapper examples.
  • Optional adapters for Playwright, llm-scraper, Crawl4AI, and Firecrawl outputs.
  • An isolated Playwright-Go acquisition boundary, pinned capability policy, and offline installation doctor for authoring-only browser tooling.
  • Explicit headless Chromium acquisition into the private raw cache with exact origins, ephemeral context destruction, and closed activity/resource bounds.
  • Deterministic terminal-guided authoring that binds explicit intent, reviewed evidence, decisions, a valid profile, and a promotable review.
  • Value-free Chromium live checks for declared locators, waits, and output shapes without macro execution.
  • Explicit short-lived screenshot/trace/HAR bundles with mandatory secret review, no publication path, and exact-ID deletion.
  • Fresh Chromium-baseline Firefox/WebKit comparisons of the same value-free profile probes, plus documented browser.1.6 contract pressure.
  • Headed manual authentication observation with separate ephemeral contexts, exact preapproved origins, step-scoped POST ceilings, and local value-free draft/review bundles.

What It Does Not Own

  • UWS schema and workflow semantics. Those live in github.com/OpenUdon/uws.
  • OpenAPI/API-source discovery and provider catalog metadata. Those belong in github.com/OpenUdon/apitools.
  • Production browser execution, runtime credential resolution, retained cookies/sessions, retries, account selection, or production side effects.
  • A general Playwright, WebDriver, Puppeteer, or scraping DSL.
  • Implicit browser launch or uploading cached content. Acquisition commands are separately selected; cache commands are local and offline, and publication has a separate verification boundary.
  • Accounts, membership, a registry database, remote writes, or deployment credentials. Static catalogs are reviewed and deployed by existing repository/hosting workflows.
  • Publication of authentication recipes through the static browser capability registry.
  • Publication of registration recipes through the static browser capability registry, or live registration/account cleanup of any kind.

Why Not Just OpenAPI?

OpenAPI should describe a stable HTTP service. If you build a browser-backed wrapper service, OpenAPI should describe that wrapper. Browsertools can also emit an advisory overlay sidecar for the wrapper, linking OpenAPI operations to reviewed browser-profile actions and review bundles.

browser-profile describes the UI binding behind the wrapper or behind a UWS browser operation:

website UI
-> browsertools-reviewed profile
-> browser runtime executes profile

or:

website UI
-> browser-backed wrapper service
-> OpenAPI describes wrapper
-> UWS binds to wrapper API

Documentation

Development

go test ./...
go vet ./...
GOWORK=off go run golang.org/x/vuln/cmd/govulncheck@v1.6.0 ./...
git diff --check
(cd ../uws && go test ./...)

Default tests use fakes and synthetic fixtures; they do not install or launch browsers and do not contact the network.

An installed-browser loopback integration test is opt-in:

BROWSERTOOLS_LIVE_TEST=1 go test ./capture -run PlaywrightLiveCaptureLoopback

Headed authentication behavior is covered by browser-free policy/state-machine tests by default. A real site is never contacted by the test suite. An installed-browser headed smoke test is separately opt-in and loopback-only:

BROWSERTOOLS_AUTH_LIVE_TEST=1 go test ./capture -run PlaywrightAuthHeadedLoopback

Rich evidence and cross-engine smoke tests are independently gated and remain loopback-only:

BROWSERTOOLS_RICH_LIVE_TEST=1 go test ./capture -run PlaywrightRichCaptureLoopback
BROWSERTOOLS_PORTABILITY_LIVE_TEST=1 go test ./capture -run PlaywrightPortabilityLoopback

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - OpenUdon/browsertools · GitHub
Skip to content

Latest commit

History

72 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

browsertools

browsertools is OpenUdon's tooling project for turning real website UI evidence into reviewed UWS browser capability profiles.

It exists for the gap where a task is exposed through a web UI and no suitable API source document is available. The output is not a browser command trace and not an OpenAPI substitute. The output is a portable, reviewed browser-profile document that a UWS workflow can bind to.

real website UI
-> browsertools using Playwright / llm-scraper / Crawl4AI / Firecrawl
-> reviewed browser-profile
-> UWS operation binds to browser-profile action

Where Browsertools Fits

OpenUdon's iCoT is the primary end-user authoring entry point across API, browser, and runtime-handoff sources. iCoT retains goal interviewing, LLM/human interaction, source selection, and package staging. For UI-only acquisition, the distributed icot executable re-executes a private copy of itself as a separate process using Browsertools' importable worker; an external browsertools CLI remains available for experts and maintainers.

Browsertools owns Playwright-based acquisition, browser safety policy, profile synthesis, and the shared validation library for browser capability and authentication profiles, plus offline validation/draft/review tooling for the separate UWS browser-registration profile. Its CLI is primarily a machine- facing protocol plus maintainer and offline tooling, not a parallel end-user authoring product. Browsertools is not the production runtime; runtime replay belongs to Udon and Browserdriver. See the canonical OpenUdon integration reference for the two integration paths and full ownership split.

For UWS 1.9.1 advisory integrity analysis, package github.com/OpenUdon/browsertools/contenttrust builds a resolver from reviewed profiles keyed by sourceDescription name. Browser-derived outputs default to untrusted while retaining their declared value shape. Navigation and option selection parameters are authority-bearing, confirmation prompts are instructions, and typed text remains data. The resolver performs no browser work and never changes validation or execution.

Authenticated live authoring uses the strict browsertools.author-session.v2 NDJSON boundary. Human-reviewed MFA kinds and up to 16 final accessibility outputs produce one private browsertools.authenticated-authoring.v2 envelope; the protocol carries no credential, page value, cookie, or browser state. See Authenticated goal-directed browser authoring.

Registration authoring has separate browser-independent contracts. V1 (browsertools.registration-author-session.v1 and private browsertools.registration-authoring.v1) remains query-free. Additive v2 (browsertools.registration-author-session.v2 and private browsertools.registration-authoring.v2) admits only bounded canonical literal structural queries and validates them on all session and retained BRP navigations. Both continue only approved-origin GET/HEAD traffic and bind one reviewed inert BRP without claiming a submit, account attempt, session, or supported runtime. Canonical unapproved non-navigation GET/HEAD subresources are counted and aborted before contact without expanding the allowlist or poisoning an otherwise clean observation; unsafe navigation, methods, and persistent channels remain fatal. A guarded typed Chromium backend and deterministic explicit candidate builder implement those contracts. The importable registrationauthorworker and browsertools registration-author-session chromium expose that backend through the same closed no-submit wire and finalize the result only under an explicit owner-only private root. See Browser registration profiles.

Page-controlled frame names cross the same canonical reduction boundary as candidate labels. Exact backend-reported MFA subsets are preserved, and the finite total timeout charges browser work rather than human credential/MFA wait time.

The authorworker package is the supported process-entry adapter for browsertools author-session chromium and the hidden iCoT worker. It accepts context, private root, optional driver directory, interruptible owned stdin, and stdout. SIGINT/SIGTERM or parent cancellation closes protocol input, then waits for browser teardown; failed close negotiation or teardown exits nonzero. Embedding it does not move Playwright into the iCoT engine or HTTP server process.

The separate registrationauthorworker is the supported process entry for no-submit BRP production. It performs read-only pinned-driver preflight, owns the closeable NDJSON input and headed browser lifetime, and creates an independently reconstructed result only after clean teardown. Its API and CLI return no result path or digest. A re-executing parent owns executable hashing, minimal child environment, and process-group termination. On Linux, an administrator-provisioned CHROME_DEVEL_SANDBOX is forwarded to Chromium only after exact mode, root ownership, link count, setuid-filesystem, resolved-path, and complete ancestor-control checks; sandbox disabling is never supported.

Accessibility-label reduction is a useful heuristic, not data loss prevention. Ordinary names, identifiers, and order numbers can remain in reduced observations and reviewed traces. Operators must review those records before retaining or sharing them.

Quick Start

go get github.com/OpenUdon/browsertools

The full pipeline from evidence to a reviewable bundle:

import (
"time""github.com/OpenUdon/browsertools/adapter""github.com/OpenUdon/browsertools/adapter/playwright""github.com/OpenUdon/browsertools/bundle""github.com/OpenUdon/browsertools/draft""github.com/OpenUdon/browsertools/evidence""github.com/OpenUdon/browsertools/profile""github.com/OpenUdon/browsertools/review"
)
// 1. Import saved Playwright snapshot as normalized evidence.a:=&playwright.Adapter{}
records, err:=a.Import(snapshotJSON, adapter.Options{
Origin: "https://example.test",
ActionHint: "read_status",
RedactionStatus: evidence.RedactionNotRequired,
})
// 2. Add explicit action intent. Evidence never invents a click or assumes// that an action is read-only.result, err:=draft.Build(records, draft.Spec{
Info: profile.Info{Title: "Example", Origin: profile.Origins{"https://example.test"}},
ObservationKind: profile.ObservationAccessibilitySnapshot,
Confidence: profile.ConfidenceMedium,
ExpiresAfter: "P30D",
Actions: map[string]draft.ActionSpec{
"read_status": {
Sequence: []profile.Step{
{Kind: profile.StepNavigate, Navigate: "/status"},
{Kind: profile.StepWaitFor, WaitFor: &profile.WaitForCondition{
Locator: &profile.Locator{Role: profile.RoleStatus, Name: "OK"},
}},
},
SideEffects: []profile.SideEffect{profile.SideEffectReadOnly},
ConfirmationPolicy: profile.ConfirmationPolicy{Required: false},
},
},
})
// 3. Build a digest-bound bundle at an explicit assessment time.assessedAt:=time.Now().UTC()
reviewed, err:=review.Build(result.Profile, records, result.Decisions, assessedAt)
iferr!=nil||!reviewed.Promotable() {
// fix gaps before promoting
}
// 4. Wrap the exact reviewed inputs in an inert publication bundle.published, err:=bundle.Build(bundle.BuildOptions{
ID: "example/status", Release: "1.0.0", Source: "reviewed_fixture",
License: "CC0-1.0", Profile: result.Profile, Review: reviewed,
Evidence: records, PublishedAt: assessedAt,
})

The CLI exposes the same offline pipeline:

go run ./cmd/browsertools profile validate --input ./profiles/example.yaml
go run ./cmd/browsertools evidence import \
--adapter playwright --input ./capture.json \
--origin https://example.test --redaction-status not_required \
--out ./evidence.json
go run ./cmd/browsertools draft build \
--evidence ./evidence.json --spec ./draft-spec.yaml \
--out ./profile.yaml
go run ./cmd/browsertools review bundle \
--profile ./profile.yaml --evidence ./evidence.json \
--at 2026-08-14T00:00:00Z --out ./review-bundle.json
go run ./cmd/browsertools revalidate check \
--profile ./profile.yaml --evidence ./evidence.json \
--at 2026-08-14T00:00:00Z --out ./revalidation.json
go run ./cmd/browsertools bundle build \
--id example/status --release 1.0.0 \
--profile ./profile.yaml --review ./review-bundle.json \
--evidence ./evidence.json --source reviewed_fixture --license CC0-1.0 \
--published-at 2026-08-14T00:00:00Z --out ./capability-bundle.json
go run ./cmd/browsertools bundle verify \
--input ./capability-bundle.json --at 2026-08-14T00:00:00Z
go run ./cmd/browsertools registry publish \
--root ./public-registry --bundle ./capability-bundle.json \
--at 2026-08-14T00:00:00Z
go run ./cmd/browsertools registry search \
--location ./public-registry --query status \
--at 2026-08-14T00:00:00Z

Browser acquisition is an explicit, separately installed authoring feature. Browsertools pins Playwright-Go v0.6201.0 (Playwright 1.62.1). Install the matching driver and Chromium deliberately, then verify the local installation:

go run github.com/mxschmitt/playwright-go/cmd/playwright@v0.6201.0 install chromium
go run ./cmd/browsertools playwright doctor --engine chromium

Before playwright doctor or an author session starts, Browsertools verifies the installed Node executable, CLI, and exact Playwright 1.62.1 package using read-only filesystem checks. It creates no cache directory, invokes no installer, and contacts no network. The doctor then starts and stops only that installed driver; its full local CLI report may include the browser executable path, while the separate UI-safe report omits executable and private paths. It does not contact a site or launch a browser. The other CLI commands remain file-first unless they are explicitly named live acquisition, check, or assisted-authentication commands.

Safe live capture is Chromium-only, headless, non-interactive, and private. It requires every exact origin and writes page material only to a finite-retention private_raw cache entry:

go run ./cmd/browsertools capture chromium \
--url https://example.test/member \
--allow-origin https://example.test \
--cache-root ./.browsertools-cache \
--action-hint read_dashboard \
--retain-for 24h

The command blocks non-GET/HEAD requests, unapproved origins, child frames, service workers, WebSockets, popups, downloads, dialogs, file choosers, and non-essential resources. It uses finite navigation, total, request, response, ARIA-depth, evidence-size, and retention limits. Only cache metadata is printed; raw ARIA/JSON-LD content is never written to stdout. See Safe live capture for the review/redaction handoff.

Explicit private screenshots, traces, and minimal-content HAR can be captured as one short-lived, non-publishable ZIP:

go run ./cmd/browsertools rich-capture chromium \
--url https://example.test/member \
--allow-origin https://example.test \
--cache-root ./.browsertools-cache \
--artifact screenshot --artifact trace --artifact har \
--retain-for 1h

The command prints only cache metadata. Export requires a new 0600 file; review for secrets is mandatory, and cache delete requires the exact digest twice. Rich artifacts have no publication or normalized-evidence path.

After normalization, the terminal guide makes every capability and safety decision explicit and emits one deterministic envelope containing the accepted spec, generated profile, action-bound evidence, ambiguity decisions, and promotable review:

go run ./cmd/browsertools guide author \
--evidence ./evidence.json \
--at 2026-08-16T12:00:00Z \
--out ./guided-authoring.json

A separately selected live check can compare declared locators, waits, and output shapes with the current page without executing any profile macro or emitting page values:

go run ./cmd/browsertools live-check chromium \
--profile ./profile.yaml \
--url https://example.test/member \
--allow-origin https://example.test \
--action read_dashboard \
--at 2026-08-16T12:00:00Z \
--out ./live-check.json

Both paths keep sequence intent, side effects, confirmation, expiry, and ambiguity decisions human-authored. The live check reuses the exact-origin ephemeral capture policy, accepts plain CSS outputs but no Playwright selector language, and writes only profile-bound match/type facts. See Guided capability authoring and live checks.

The same profile-derived read-only checks can be compared without locator rewrites across explicitly installed engines:

go run ./cmd/browsertools portability check \
--profile ./profile.yaml \
--url https://example.test/member \
--allow-origin https://example.test \
--action read_dashboard \
--engine chromium --engine firefox --engine webkit \
--out ./portability.json

Chromium is the required baseline. Missing engines and shape differences are fixed value-free diagnostics, not silent fallbacks. See Private rich evidence and cross-engine portability.

Portable sign-in recipes use a separate additive contract and remain local to the workflow package:

go run ./cmd/browsertools auth-draft build \
--spec ./authentication-spec.yaml \
--out ./browser-authentication/member.yaml
go run ./cmd/browsertools auth-profile validate \
--input ./browser-authentication/member.yaml \
--at 2026-08-16T00:00:00Z
go run ./cmd/browsertools auth-review bundle \
--profile ./browser-authentication/member.yaml \
--at 2026-08-16T00:00:00Z \
--out ./browser-authentication/member.review.json

An explicit headed authoring command can then observe the exact recipe while the operator enters credentials and completes MFA directly in the browser:

go run ./cmd/browsertools auth-assist chromium \
--profile ./browser-authentication/member.yaml \
--flow member_login_push \
--approve-origin https://members.example.test \
--approve-origin https://login.example.test \
--post-budget member_login_push:3=2 \
--out ./browser-authentication/member.assisted.json

The profile supplies every locator, challenge alternative, submit step, and success condition; Browsertools does not infer them. Each selected flow runs in a separate visible ephemeral context. Browsertools navigates declared URLs and counts declared accessibility locators, but the operator performs every credential, click, and challenge step and signals completion with an empty terminal line. A POST is blocked unless its exact zero-based flow step has an explicit bounded --post-budget; all other mutating methods are blocked.

The 0600 output is created only after every context has closed and contains a selected uws.browser-authentication.1.0 profile, its digest-bound review, and value-free origin/count/request evidence. It cannot use stdin for a profile, stdout for the artifact, or overwrite a path. Authentication recipes are also excluded from static registry publication. Actual credentials, MFA responses, OAuth state, cookies, storage, and sessions stay in the browser or downstream private runtime. See Browser authentication profiles.

Account registration uses a separate explicitly mutating contract. Browsertools can validate, deterministically build, and digest-review only the inert recipe:

go run ./cmd/browsertools registration-draft build \
--spec ./registration-spec.yaml \
--out ./browser-registration/dedicated-test-user.yaml
go run ./cmd/browsertools registration-profile validate \
--input ./browser-registration/dedicated-test-user.yaml \
--at 2026-08-25T00:00:00Z
go run ./cmd/browsertools registration-review bundle \
--profile ./browser-registration/dedicated-test-user.yaml \
--at 2026-08-25T00:00:00Z \
--out ./browser-registration/dedicated-test-user.review.json

These commands are file-only and never launch a browser, contact a target, resolve a symbolic credential, submit a registration, handle CAPTCHA/MFA/email verification, approve a run, or perform cleanup. Registration profiles and reviews remain package-local and are excluded from the browser capability registry. See Browser registration profiles.

The typed registrationauthor.Build path combines one current reduced registration observation with a complete registrationdraft.Spec, exact reviewed candidate IDs, selected submit candidate and flow, approved origins, and explicit fixed call controls. It reconstructs the current-generation candidate IDs, binds the one accessibility-name submit, and emits the exact M26 review message without inferring any profile or cleanup field. After clean session teardown, registrationauthorresult.FinalizePrivate independently reconstructs and strict-decodes the M26 result before and after an anchored owner-only, create-once write; its path remains process-private.

The standalone producer uses that complete path:

browsertools registration-author-session chromium \
--private-root ./private-registration-results \
--driver-dir "$PLAYWRIGHT_DRIVER_PATH"

Stdin and stdout are reserved for registration author-session NDJSON. The worker defaults to v1; --protocol v2 deliberately selects the additive retained-query contract and guarded Chromium routing. The private root must already be a mode-0700 directory. The command never prints the resulting file name or digest, and it provides no registration runtime or submit command.

Caller-supplied raw captures and derived artifacts can be kept in an explicit private local cache. Raw entries can never be publication eligible:

go run ./cmd/browsertools cache put \
--root ./.browsertools-cache --input ./capture.json \
--kind private_raw --media-type application/json \
--created-at 2026-08-14T00:00:00Z
go run ./cmd/browsertools cache list \
--root ./.browsertools-cache --at 2026-08-14T12:00:00Z
go run ./cmd/browsertools cache prune \
--root ./.browsertools-cache --at 2026-09-14T00:00:00Z
go run ./cmd/browsertools cache delete \
--root ./.browsertools-cache --id sha256:EXACT_ID --confirm-id sha256:EXACT_ID

What It Owns

  • A complete typed model and validation helpers for UWS browser-profile documents.
  • Typed validation, deterministic drafting, digest-bound review, freshness, and local discovery for package-local uws.browser-authentication.1.0 recipes.
  • Typed offline validation, deterministic explicit drafting, digest-bound review, and freshness for package-local uws.browser-registration.1.0 recipes.
  • Secret-free evidence records from browser and scraper tooling.
  • Draft profile generation from reviewed evidence.
  • Review bundles with validation, confidence, expiry, side-effect, and revalidation notes.
  • Deterministic fixture-only revalidation and digest-bound promotion gates.
  • A bounded, content-addressed private cache for caller-supplied experiences, normalized evidence, profiles, and review bundles.
  • Canonical, digest-bound, lifecycle-assessed publication bundles for reviewed profiles, safe evidence, and optional inert UWS companions.
  • A service-free static registry layout, atomic local publisher, bounded local/HTTPS reader, and local browser-source discovery report.
  • Browser-profile, scraper/crawler, and browser-backed wrapper examples.
  • Optional adapters for Playwright, llm-scraper, Crawl4AI, and Firecrawl outputs.
  • An isolated Playwright-Go acquisition boundary, pinned capability policy, and offline installation doctor for authoring-only browser tooling.
  • Explicit headless Chromium acquisition into the private raw cache with exact origins, ephemeral context destruction, and closed activity/resource bounds.
  • Deterministic terminal-guided authoring that binds explicit intent, reviewed evidence, decisions, a valid profile, and a promotable review.
  • Value-free Chromium live checks for declared locators, waits, and output shapes without macro execution.
  • Explicit short-lived screenshot/trace/HAR bundles with mandatory secret review, no publication path, and exact-ID deletion.
  • Fresh Chromium-baseline Firefox/WebKit comparisons of the same value-free profile probes, plus documented browser.1.6 contract pressure.
  • Headed manual authentication observation with separate ephemeral contexts, exact preapproved origins, step-scoped POST ceilings, and local value-free draft/review bundles.

What It Does Not Own

  • UWS schema and workflow semantics. Those live in github.com/OpenUdon/uws.
  • OpenAPI/API-source discovery and provider catalog metadata. Those belong in github.com/OpenUdon/apitools.
  • Production browser execution, runtime credential resolution, retained cookies/sessions, retries, account selection, or production side effects.
  • A general Playwright, WebDriver, Puppeteer, or scraping DSL.
  • Implicit browser launch or uploading cached content. Acquisition commands are separately selected; cache commands are local and offline, and publication has a separate verification boundary.
  • Accounts, membership, a registry database, remote writes, or deployment credentials. Static catalogs are reviewed and deployed by existing repository/hosting workflows.
  • Publication of authentication recipes through the static browser capability registry.
  • Publication of registration recipes through the static browser capability registry, or live registration/account cleanup of any kind.

Why Not Just OpenAPI?

OpenAPI should describe a stable HTTP service. If you build a browser-backed wrapper service, OpenAPI should describe that wrapper. Browsertools can also emit an advisory overlay sidecar for the wrapper, linking OpenAPI operations to reviewed browser-profile actions and review bundles.

browser-profile describes the UI binding behind the wrapper or behind a UWS browser operation:

website UI
-> browsertools-reviewed profile
-> browser runtime executes profile

or:

website UI
-> browser-backed wrapper service
-> OpenAPI describes wrapper
-> UWS binds to wrapper API

Documentation

Development

go test ./...
go vet ./...
GOWORK=off go run golang.org/x/vuln/cmd/govulncheck@v1.6.0 ./...
git diff --check
(cd ../uws && go test ./...)

Default tests use fakes and synthetic fixtures; they do not install or launch browsers and do not contact the network.

An installed-browser loopback integration test is opt-in:

BROWSERTOOLS_LIVE_TEST=1 go test ./capture -run PlaywrightLiveCaptureLoopback

Headed authentication behavior is covered by browser-free policy/state-machine tests by default. A real site is never contacted by the test suite. An installed-browser headed smoke test is separately opt-in and loopback-only:

BROWSERTOOLS_AUTH_LIVE_TEST=1 go test ./capture -run PlaywrightAuthHeadedLoopback

Rich evidence and cross-engine smoke tests are independently gated and remain loopback-only:

BROWSERTOOLS_RICH_LIVE_TEST=1 go test ./capture -run PlaywrightRichCaptureLoopback
BROWSERTOOLS_PORTABILITY_LIVE_TEST=1 go test ./capture -run PlaywrightPortabilityLoopback

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - OpenUdon/browsertools · GitHub
Skip to content

Latest commit

History

72 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

browsertools

browsertools is OpenUdon's tooling project for turning real website UI evidence into reviewed UWS browser capability profiles.

It exists for the gap where a task is exposed through a web UI and no suitable API source document is available. The output is not a browser command trace and not an OpenAPI substitute. The output is a portable, reviewed browser-profile document that a UWS workflow can bind to.

real website UI
-> browsertools using Playwright / llm-scraper / Crawl4AI / Firecrawl
-> reviewed browser-profile
-> UWS operation binds to browser-profile action

Where Browsertools Fits

OpenUdon's iCoT is the primary end-user authoring entry point across API, browser, and runtime-handoff sources. iCoT retains goal interviewing, LLM/human interaction, source selection, and package staging. For UI-only acquisition, the distributed icot executable re-executes a private copy of itself as a separate process using Browsertools' importable worker; an external browsertools CLI remains available for experts and maintainers.

Browsertools owns Playwright-based acquisition, browser safety policy, profile synthesis, and the shared validation library for browser capability and authentication profiles, plus offline validation/draft/review tooling for the separate UWS browser-registration profile. Its CLI is primarily a machine- facing protocol plus maintainer and offline tooling, not a parallel end-user authoring product. Browsertools is not the production runtime; runtime replay belongs to Udon and Browserdriver. See the canonical OpenUdon integration reference for the two integration paths and full ownership split.

For UWS 1.9.1 advisory integrity analysis, package github.com/OpenUdon/browsertools/contenttrust builds a resolver from reviewed profiles keyed by sourceDescription name. Browser-derived outputs default to untrusted while retaining their declared value shape. Navigation and option selection parameters are authority-bearing, confirmation prompts are instructions, and typed text remains data. The resolver performs no browser work and never changes validation or execution.

Authenticated live authoring uses the strict browsertools.author-session.v2 NDJSON boundary. Human-reviewed MFA kinds and up to 16 final accessibility outputs produce one private browsertools.authenticated-authoring.v2 envelope; the protocol carries no credential, page value, cookie, or browser state. See Authenticated goal-directed browser authoring.

Registration authoring has separate browser-independent contracts. V1 (browsertools.registration-author-session.v1 and private browsertools.registration-authoring.v1) remains query-free. Additive v2 (browsertools.registration-author-session.v2 and private browsertools.registration-authoring.v2) admits only bounded canonical literal structural queries and validates them on all session and retained BRP navigations. Both continue only approved-origin GET/HEAD traffic and bind one reviewed inert BRP without claiming a submit, account attempt, session, or supported runtime. Canonical unapproved non-navigation GET/HEAD subresources are counted and aborted before contact without expanding the allowlist or poisoning an otherwise clean observation; unsafe navigation, methods, and persistent channels remain fatal. A guarded typed Chromium backend and deterministic explicit candidate builder implement those contracts. The importable registrationauthorworker and browsertools registration-author-session chromium expose that backend through the same closed no-submit wire and finalize the result only under an explicit owner-only private root. See Browser registration profiles.

Page-controlled frame names cross the same canonical reduction boundary as candidate labels. Exact backend-reported MFA subsets are preserved, and the finite total timeout charges browser work rather than human credential/MFA wait time.

The authorworker package is the supported process-entry adapter for browsertools author-session chromium and the hidden iCoT worker. It accepts context, private root, optional driver directory, interruptible owned stdin, and stdout. SIGINT/SIGTERM or parent cancellation closes protocol input, then waits for browser teardown; failed close negotiation or teardown exits nonzero. Embedding it does not move Playwright into the iCoT engine or HTTP server process.

The separate registrationauthorworker is the supported process entry for no-submit BRP production. It performs read-only pinned-driver preflight, owns the closeable NDJSON input and headed browser lifetime, and creates an independently reconstructed result only after clean teardown. Its API and CLI return no result path or digest. A re-executing parent owns executable hashing, minimal child environment, and process-group termination. On Linux, an administrator-provisioned CHROME_DEVEL_SANDBOX is forwarded to Chromium only after exact mode, root ownership, link count, setuid-filesystem, resolved-path, and complete ancestor-control checks; sandbox disabling is never supported.

Accessibility-label reduction is a useful heuristic, not data loss prevention. Ordinary names, identifiers, and order numbers can remain in reduced observations and reviewed traces. Operators must review those records before retaining or sharing them.

Quick Start

go get github.com/OpenUdon/browsertools

The full pipeline from evidence to a reviewable bundle:

import (
"time""github.com/OpenUdon/browsertools/adapter""github.com/OpenUdon/browsertools/adapter/playwright""github.com/OpenUdon/browsertools/bundle""github.com/OpenUdon/browsertools/draft""github.com/OpenUdon/browsertools/evidence""github.com/OpenUdon/browsertools/profile""github.com/OpenUdon/browsertools/review"
)
// 1. Import saved Playwright snapshot as normalized evidence.a:=&playwright.Adapter{}
records, err:=a.Import(snapshotJSON, adapter.Options{
Origin: "https://example.test",
ActionHint: "read_status",
RedactionStatus: evidence.RedactionNotRequired,
})
// 2. Add explicit action intent. Evidence never invents a click or assumes// that an action is read-only.result, err:=draft.Build(records, draft.Spec{
Info: profile.Info{Title: "Example", Origin: profile.Origins{"https://example.test"}},
ObservationKind: profile.ObservationAccessibilitySnapshot,
Confidence: profile.ConfidenceMedium,
ExpiresAfter: "P30D",
Actions: map[string]draft.ActionSpec{
"read_status": {
Sequence: []profile.Step{
{Kind: profile.StepNavigate, Navigate: "/status"},
{Kind: profile.StepWaitFor, WaitFor: &profile.WaitForCondition{
Locator: &profile.Locator{Role: profile.RoleStatus, Name: "OK"},
}},
},
SideEffects: []profile.SideEffect{profile.SideEffectReadOnly},
ConfirmationPolicy: profile.ConfirmationPolicy{Required: false},
},
},
})
// 3. Build a digest-bound bundle at an explicit assessment time.assessedAt:=time.Now().UTC()
reviewed, err:=review.Build(result.Profile, records, result.Decisions, assessedAt)
iferr!=nil||!reviewed.Promotable() {
// fix gaps before promoting
}
// 4. Wrap the exact reviewed inputs in an inert publication bundle.published, err:=bundle.Build(bundle.BuildOptions{
ID: "example/status", Release: "1.0.0", Source: "reviewed_fixture",
License: "CC0-1.0", Profile: result.Profile, Review: reviewed,
Evidence: records, PublishedAt: assessedAt,
})

The CLI exposes the same offline pipeline:

go run ./cmd/browsertools profile validate --input ./profiles/example.yaml
go run ./cmd/browsertools evidence import \
--adapter playwright --input ./capture.json \
--origin https://example.test --redaction-status not_required \
--out ./evidence.json
go run ./cmd/browsertools draft build \
--evidence ./evidence.json --spec ./draft-spec.yaml \
--out ./profile.yaml
go run ./cmd/browsertools review bundle \
--profile ./profile.yaml --evidence ./evidence.json \
--at 2026-08-14T00:00:00Z --out ./review-bundle.json
go run ./cmd/browsertools revalidate check \
--profile ./profile.yaml --evidence ./evidence.json \
--at 2026-08-14T00:00:00Z --out ./revalidation.json
go run ./cmd/browsertools bundle build \
--id example/status --release 1.0.0 \
--profile ./profile.yaml --review ./review-bundle.json \
--evidence ./evidence.json --source reviewed_fixture --license CC0-1.0 \
--published-at 2026-08-14T00:00:00Z --out ./capability-bundle.json
go run ./cmd/browsertools bundle verify \
--input ./capability-bundle.json --at 2026-08-14T00:00:00Z
go run ./cmd/browsertools registry publish \
--root ./public-registry --bundle ./capability-bundle.json \
--at 2026-08-14T00:00:00Z
go run ./cmd/browsertools registry search \
--location ./public-registry --query status \
--at 2026-08-14T00:00:00Z

Browser acquisition is an explicit, separately installed authoring feature. Browsertools pins Playwright-Go v0.6201.0 (Playwright 1.62.1). Install the matching driver and Chromium deliberately, then verify the local installation:

go run github.com/mxschmitt/playwright-go/cmd/playwright@v0.6201.0 install chromium
go run ./cmd/browsertools playwright doctor --engine chromium

Before playwright doctor or an author session starts, Browsertools verifies the installed Node executable, CLI, and exact Playwright 1.62.1 package using read-only filesystem checks. It creates no cache directory, invokes no installer, and contacts no network. The doctor then starts and stops only that installed driver; its full local CLI report may include the browser executable path, while the separate UI-safe report omits executable and private paths. It does not contact a site or launch a browser. The other CLI commands remain file-first unless they are explicitly named live acquisition, check, or assisted-authentication commands.

Safe live capture is Chromium-only, headless, non-interactive, and private. It requires every exact origin and writes page material only to a finite-retention private_raw cache entry:

go run ./cmd/browsertools capture chromium \
--url https://example.test/member \
--allow-origin https://example.test \
--cache-root ./.browsertools-cache \
--action-hint read_dashboard \
--retain-for 24h

The command blocks non-GET/HEAD requests, unapproved origins, child frames, service workers, WebSockets, popups, downloads, dialogs, file choosers, and non-essential resources. It uses finite navigation, total, request, response, ARIA-depth, evidence-size, and retention limits. Only cache metadata is printed; raw ARIA/JSON-LD content is never written to stdout. See Safe live capture for the review/redaction handoff.

Explicit private screenshots, traces, and minimal-content HAR can be captured as one short-lived, non-publishable ZIP:

go run ./cmd/browsertools rich-capture chromium \
--url https://example.test/member \
--allow-origin https://example.test \
--cache-root ./.browsertools-cache \
--artifact screenshot --artifact trace --artifact har \
--retain-for 1h

The command prints only cache metadata. Export requires a new 0600 file; review for secrets is mandatory, and cache delete requires the exact digest twice. Rich artifacts have no publication or normalized-evidence path.

After normalization, the terminal guide makes every capability and safety decision explicit and emits one deterministic envelope containing the accepted spec, generated profile, action-bound evidence, ambiguity decisions, and promotable review:

go run ./cmd/browsertools guide author \
--evidence ./evidence.json \
--at 2026-08-16T12:00:00Z \
--out ./guided-authoring.json

A separately selected live check can compare declared locators, waits, and output shapes with the current page without executing any profile macro or emitting page values:

go run ./cmd/browsertools live-check chromium \
--profile ./profile.yaml \
--url https://example.test/member \
--allow-origin https://example.test \
--action read_dashboard \
--at 2026-08-16T12:00:00Z \
--out ./live-check.json

Both paths keep sequence intent, side effects, confirmation, expiry, and ambiguity decisions human-authored. The live check reuses the exact-origin ephemeral capture policy, accepts plain CSS outputs but no Playwright selector language, and writes only profile-bound match/type facts. See Guided capability authoring and live checks.

The same profile-derived read-only checks can be compared without locator rewrites across explicitly installed engines:

go run ./cmd/browsertools portability check \
--profile ./profile.yaml \
--url https://example.test/member \
--allow-origin https://example.test \
--action read_dashboard \
--engine chromium --engine firefox --engine webkit \
--out ./portability.json

Chromium is the required baseline. Missing engines and shape differences are fixed value-free diagnostics, not silent fallbacks. See Private rich evidence and cross-engine portability.

Portable sign-in recipes use a separate additive contract and remain local to the workflow package:

go run ./cmd/browsertools auth-draft build \
--spec ./authentication-spec.yaml \
--out ./browser-authentication/member.yaml
go run ./cmd/browsertools auth-profile validate \
--input ./browser-authentication/member.yaml \
--at 2026-08-16T00:00:00Z
go run ./cmd/browsertools auth-review bundle \
--profile ./browser-authentication/member.yaml \
--at 2026-08-16T00:00:00Z \
--out ./browser-authentication/member.review.json

An explicit headed authoring command can then observe the exact recipe while the operator enters credentials and completes MFA directly in the browser:

go run ./cmd/browsertools auth-assist chromium \
--profile ./browser-authentication/member.yaml \
--flow member_login_push \
--approve-origin https://members.example.test \
--approve-origin https://login.example.test \
--post-budget member_login_push:3=2 \
--out ./browser-authentication/member.assisted.json

The profile supplies every locator, challenge alternative, submit step, and success condition; Browsertools does not infer them. Each selected flow runs in a separate visible ephemeral context. Browsertools navigates declared URLs and counts declared accessibility locators, but the operator performs every credential, click, and challenge step and signals completion with an empty terminal line. A POST is blocked unless its exact zero-based flow step has an explicit bounded --post-budget; all other mutating methods are blocked.

The 0600 output is created only after every context has closed and contains a selected uws.browser-authentication.1.0 profile, its digest-bound review, and value-free origin/count/request evidence. It cannot use stdin for a profile, stdout for the artifact, or overwrite a path. Authentication recipes are also excluded from static registry publication. Actual credentials, MFA responses, OAuth state, cookies, storage, and sessions stay in the browser or downstream private runtime. See Browser authentication profiles.

Account registration uses a separate explicitly mutating contract. Browsertools can validate, deterministically build, and digest-review only the inert recipe:

go run ./cmd/browsertools registration-draft build \
--spec ./registration-spec.yaml \
--out ./browser-registration/dedicated-test-user.yaml
go run ./cmd/browsertools registration-profile validate \
--input ./browser-registration/dedicated-test-user.yaml \
--at 2026-08-25T00:00:00Z
go run ./cmd/browsertools registration-review bundle \
--profile ./browser-registration/dedicated-test-user.yaml \
--at 2026-08-25T00:00:00Z \
--out ./browser-registration/dedicated-test-user.review.json

These commands are file-only and never launch a browser, contact a target, resolve a symbolic credential, submit a registration, handle CAPTCHA/MFA/email verification, approve a run, or perform cleanup. Registration profiles and reviews remain package-local and are excluded from the browser capability registry. See Browser registration profiles.

The typed registrationauthor.Build path combines one current reduced registration observation with a complete registrationdraft.Spec, exact reviewed candidate IDs, selected submit candidate and flow, approved origins, and explicit fixed call controls. It reconstructs the current-generation candidate IDs, binds the one accessibility-name submit, and emits the exact M26 review message without inferring any profile or cleanup field. After clean session teardown, registrationauthorresult.FinalizePrivate independently reconstructs and strict-decodes the M26 result before and after an anchored owner-only, create-once write; its path remains process-private.

The standalone producer uses that complete path:

browsertools registration-author-session chromium \
--private-root ./private-registration-results \
--driver-dir "$PLAYWRIGHT_DRIVER_PATH"

Stdin and stdout are reserved for registration author-session NDJSON. The worker defaults to v1; --protocol v2 deliberately selects the additive retained-query contract and guarded Chromium routing. The private root must already be a mode-0700 directory. The command never prints the resulting file name or digest, and it provides no registration runtime or submit command.

Caller-supplied raw captures and derived artifacts can be kept in an explicit private local cache. Raw entries can never be publication eligible:

go run ./cmd/browsertools cache put \
--root ./.browsertools-cache --input ./capture.json \
--kind private_raw --media-type application/json \
--created-at 2026-08-14T00:00:00Z
go run ./cmd/browsertools cache list \
--root ./.browsertools-cache --at 2026-08-14T12:00:00Z
go run ./cmd/browsertools cache prune \
--root ./.browsertools-cache --at 2026-09-14T00:00:00Z
go run ./cmd/browsertools cache delete \
--root ./.browsertools-cache --id sha256:EXACT_ID --confirm-id sha256:EXACT_ID

What It Owns

  • A complete typed model and validation helpers for UWS browser-profile documents.
  • Typed validation, deterministic drafting, digest-bound review, freshness, and local discovery for package-local uws.browser-authentication.1.0 recipes.
  • Typed offline validation, deterministic explicit drafting, digest-bound review, and freshness for package-local uws.browser-registration.1.0 recipes.
  • Secret-free evidence records from browser and scraper tooling.
  • Draft profile generation from reviewed evidence.
  • Review bundles with validation, confidence, expiry, side-effect, and revalidation notes.
  • Deterministic fixture-only revalidation and digest-bound promotion gates.
  • A bounded, content-addressed private cache for caller-supplied experiences, normalized evidence, profiles, and review bundles.
  • Canonical, digest-bound, lifecycle-assessed publication bundles for reviewed profiles, safe evidence, and optional inert UWS companions.
  • A service-free static registry layout, atomic local publisher, bounded local/HTTPS reader, and local browser-source discovery report.
  • Browser-profile, scraper/crawler, and browser-backed wrapper examples.
  • Optional adapters for Playwright, llm-scraper, Crawl4AI, and Firecrawl outputs.
  • An isolated Playwright-Go acquisition boundary, pinned capability policy, and offline installation doctor for authoring-only browser tooling.
  • Explicit headless Chromium acquisition into the private raw cache with exact origins, ephemeral context destruction, and closed activity/resource bounds.
  • Deterministic terminal-guided authoring that binds explicit intent, reviewed evidence, decisions, a valid profile, and a promotable review.
  • Value-free Chromium live checks for declared locators, waits, and output shapes without macro execution.
  • Explicit short-lived screenshot/trace/HAR bundles with mandatory secret review, no publication path, and exact-ID deletion.
  • Fresh Chromium-baseline Firefox/WebKit comparisons of the same value-free profile probes, plus documented browser.1.6 contract pressure.
  • Headed manual authentication observation with separate ephemeral contexts, exact preapproved origins, step-scoped POST ceilings, and local value-free draft/review bundles.

What It Does Not Own

  • UWS schema and workflow semantics. Those live in github.com/OpenUdon/uws.
  • OpenAPI/API-source discovery and provider catalog metadata. Those belong in github.com/OpenUdon/apitools.
  • Production browser execution, runtime credential resolution, retained cookies/sessions, retries, account selection, or production side effects.
  • A general Playwright, WebDriver, Puppeteer, or scraping DSL.
  • Implicit browser launch or uploading cached content. Acquisition commands are separately selected; cache commands are local and offline, and publication has a separate verification boundary.
  • Accounts, membership, a registry database, remote writes, or deployment credentials. Static catalogs are reviewed and deployed by existing repository/hosting workflows.
  • Publication of authentication recipes through the static browser capability registry.
  • Publication of registration recipes through the static browser capability registry, or live registration/account cleanup of any kind.

Why Not Just OpenAPI?

OpenAPI should describe a stable HTTP service. If you build a browser-backed wrapper service, OpenAPI should describe that wrapper. Browsertools can also emit an advisory overlay sidecar for the wrapper, linking OpenAPI operations to reviewed browser-profile actions and review bundles.

browser-profile describes the UI binding behind the wrapper or behind a UWS browser operation:

website UI
-> browsertools-reviewed profile
-> browser runtime executes profile

or:

website UI
-> browser-backed wrapper service
-> OpenAPI describes wrapper
-> UWS binds to wrapper API

Documentation

Development

go test ./...
go vet ./...
GOWORK=off go run golang.org/x/vuln/cmd/govulncheck@v1.6.0 ./...
git diff --check
(cd ../uws && go test ./...)

Default tests use fakes and synthetic fixtures; they do not install or launch browsers and do not contact the network.

An installed-browser loopback integration test is opt-in:

BROWSERTOOLS_LIVE_TEST=1 go test ./capture -run PlaywrightLiveCaptureLoopback

Headed authentication behavior is covered by browser-free policy/state-machine tests by default. A real site is never contacted by the test suite. An installed-browser headed smoke test is separately opt-in and loopback-only:

BROWSERTOOLS_AUTH_LIVE_TEST=1 go test ./capture -run PlaywrightAuthHeadedLoopback

Rich evidence and cross-engine smoke tests are independently gated and remain loopback-only:

BROWSERTOOLS_RICH_LIVE_TEST=1 go test ./capture -run PlaywrightRichCaptureLoopback
BROWSERTOOLS_PORTABILITY_LIVE_TEST=1 go test ./capture -run PlaywrightPortabilityLoopback

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' GitHub - OpenUdon/browsertools · GitHub
Skip to content

Latest commit

History

72 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

browsertools

browsertools is OpenUdon's tooling project for turning real website UI evidence into reviewed UWS browser capability profiles.

It exists for the gap where a task is exposed through a web UI and no suitable API source document is available. The output is not a browser command trace and not an OpenAPI substitute. The output is a portable, reviewed browser-profile document that a UWS workflow can bind to.

real website UI
-> browsertools using Playwright / llm-scraper / Crawl4AI / Firecrawl
-> reviewed browser-profile
-> UWS operation binds to browser-profile action

Where Browsertools Fits

OpenUdon's iCoT is the primary end-user authoring entry point across API, browser, and runtime-handoff sources. iCoT retains goal interviewing, LLM/human interaction, source selection, and package staging. For UI-only acquisition, the distributed icot executable re-executes a private copy of itself as a separate process using Browsertools' importable worker; an external browsertools CLI remains available for experts and maintainers.

Browsertools owns Playwright-based acquisition, browser safety policy, profile synthesis, and the shared validation library for browser capability and authentication profiles, plus offline validation/draft/review tooling for the separate UWS browser-registration profile. Its CLI is primarily a machine- facing protocol plus maintainer and offline tooling, not a parallel end-user authoring product. Browsertools is not the production runtime; runtime replay belongs to Udon and Browserdriver. See the canonical OpenUdon integration reference for the two integration paths and full ownership split.

For UWS 1.9.1 advisory integrity analysis, package github.com/OpenUdon/browsertools/contenttrust builds a resolver from reviewed profiles keyed by sourceDescription name. Browser-derived outputs default to untrusted while retaining their declared value shape. Navigation and option selection parameters are authority-bearing, confirmation prompts are instructions, and typed text remains data. The resolver performs no browser work and never changes validation or execution.

Authenticated live authoring uses the strict browsertools.author-session.v2 NDJSON boundary. Human-reviewed MFA kinds and up to 16 final accessibility outputs produce one private browsertools.authenticated-authoring.v2 envelope; the protocol carries no credential, page value, cookie, or browser state. See Authenticated goal-directed browser authoring.

Registration authoring has separate browser-independent contracts. V1 (browsertools.registration-author-session.v1 and private browsertools.registration-authoring.v1) remains query-free. Additive v2 (browsertools.registration-author-session.v2 and private browsertools.registration-authoring.v2) admits only bounded canonical literal structural queries and validates them on all session and retained BRP navigations. Both continue only approved-origin GET/HEAD traffic and bind one reviewed inert BRP without claiming a submit, account attempt, session, or supported runtime. Canonical unapproved non-navigation GET/HEAD subresources are counted and aborted before contact without expanding the allowlist or poisoning an otherwise clean observation; unsafe navigation, methods, and persistent channels remain fatal. A guarded typed Chromium backend and deterministic explicit candidate builder implement those contracts. The importable registrationauthorworker and browsertools registration-author-session chromium expose that backend through the same closed no-submit wire and finalize the result only under an explicit owner-only private root. See Browser registration profiles.

Page-controlled frame names cross the same canonical reduction boundary as candidate labels. Exact backend-reported MFA subsets are preserved, and the finite total timeout charges browser work rather than human credential/MFA wait time.

The authorworker package is the supported process-entry adapter for browsertools author-session chromium and the hidden iCoT worker. It accepts context, private root, optional driver directory, interruptible owned stdin, and stdout. SIGINT/SIGTERM or parent cancellation closes protocol input, then waits for browser teardown; failed close negotiation or teardown exits nonzero. Embedding it does not move Playwright into the iCoT engine or HTTP server process.

The separate registrationauthorworker is the supported process entry for no-submit BRP production. It performs read-only pinned-driver preflight, owns the closeable NDJSON input and headed browser lifetime, and creates an independently reconstructed result only after clean teardown. Its API and CLI return no result path or digest. A re-executing parent owns executable hashing, minimal child environment, and process-group termination. On Linux, an administrator-provisioned CHROME_DEVEL_SANDBOX is forwarded to Chromium only after exact mode, root ownership, link count, setuid-filesystem, resolved-path, and complete ancestor-control checks; sandbox disabling is never supported.

Accessibility-label reduction is a useful heuristic, not data loss prevention. Ordinary names, identifiers, and order numbers can remain in reduced observations and reviewed traces. Operators must review those records before retaining or sharing them.

Quick Start

go get github.com/OpenUdon/browsertools

The full pipeline from evidence to a reviewable bundle:

import (
"time""github.com/OpenUdon/browsertools/adapter""github.com/OpenUdon/browsertools/adapter/playwright""github.com/OpenUdon/browsertools/bundle""github.com/OpenUdon/browsertools/draft""github.com/OpenUdon/browsertools/evidence""github.com/OpenUdon/browsertools/profile""github.com/OpenUdon/browsertools/review"
)
// 1. Import saved Playwright snapshot as normalized evidence.a:=&playwright.Adapter{}
records, err:=a.Import(snapshotJSON, adapter.Options{
Origin: "https://example.test",
ActionHint: "read_status",
RedactionStatus: evidence.RedactionNotRequired,
})
// 2. Add explicit action intent. Evidence never invents a click or assumes// that an action is read-only.result, err:=draft.Build(records, draft.Spec{
Info: profile.Info{Title: "Example", Origin: profile.Origins{"https://example.test"}},
ObservationKind: profile.ObservationAccessibilitySnapshot,
Confidence: profile.ConfidenceMedium,
ExpiresAfter: "P30D",
Actions: map[string]draft.ActionSpec{
"read_status": {
Sequence: []profile.Step{
{Kind: profile.StepNavigate, Navigate: "/status"},
{Kind: profile.StepWaitFor, WaitFor: &profile.WaitForCondition{
Locator: &profile.Locator{Role: profile.RoleStatus, Name: "OK"},
}},
},
SideEffects: []profile.SideEffect{profile.SideEffectReadOnly},
ConfirmationPolicy: profile.ConfirmationPolicy{Required: false},
},
},
})
// 3. Build a digest-bound bundle at an explicit assessment time.assessedAt:=time.Now().UTC()
reviewed, err:=review.Build(result.Profile, records, result.Decisions, assessedAt)
iferr!=nil||!reviewed.Promotable() {
// fix gaps before promoting
}
// 4. Wrap the exact reviewed inputs in an inert publication bundle.published, err:=bundle.Build(bundle.BuildOptions{
ID: "example/status", Release: "1.0.0", Source: "reviewed_fixture",
License: "CC0-1.0", Profile: result.Profile, Review: reviewed,
Evidence: records, PublishedAt: assessedAt,
})

The CLI exposes the same offline pipeline:

go run ./cmd/browsertools profile validate --input ./profiles/example.yaml
go run ./cmd/browsertools evidence import \
--adapter playwright --input ./capture.json \
--origin https://example.test --redaction-status not_required \
--out ./evidence.json
go run ./cmd/browsertools draft build \
--evidence ./evidence.json --spec ./draft-spec.yaml \
--out ./profile.yaml
go run ./cmd/browsertools review bundle \
--profile ./profile.yaml --evidence ./evidence.json \
--at 2026-08-14T00:00:00Z --out ./review-bundle.json
go run ./cmd/browsertools revalidate check \
--profile ./profile.yaml --evidence ./evidence.json \
--at 2026-08-14T00:00:00Z --out ./revalidation.json
go run ./cmd/browsertools bundle build \
--id example/status --release 1.0.0 \
--profile ./profile.yaml --review ./review-bundle.json \
--evidence ./evidence.json --source reviewed_fixture --license CC0-1.0 \
--published-at 2026-08-14T00:00:00Z --out ./capability-bundle.json
go run ./cmd/browsertools bundle verify \
--input ./capability-bundle.json --at 2026-08-14T00:00:00Z
go run ./cmd/browsertools registry publish \
--root ./public-registry --bundle ./capability-bundle.json \
--at 2026-08-14T00:00:00Z
go run ./cmd/browsertools registry search \
--location ./public-registry --query status \
--at 2026-08-14T00:00:00Z

Browser acquisition is an explicit, separately installed authoring feature. Browsertools pins Playwright-Go v0.6201.0 (Playwright 1.62.1). Install the matching driver and Chromium deliberately, then verify the local installation:

go run github.com/mxschmitt/playwright-go/cmd/playwright@v0.6201.0 install chromium
go run ./cmd/browsertools playwright doctor --engine chromium

Before playwright doctor or an author session starts, Browsertools verifies the installed Node executable, CLI, and exact Playwright 1.62.1 package using read-only filesystem checks. It creates no cache directory, invokes no installer, and contacts no network. The doctor then starts and stops only that installed driver; its full local CLI report may include the browser executable path, while the separate UI-safe report omits executable and private paths. It does not contact a site or launch a browser. The other CLI commands remain file-first unless they are explicitly named live acquisition, check, or assisted-authentication commands.

Safe live capture is Chromium-only, headless, non-interactive, and private. It requires every exact origin and writes page material only to a finite-retention private_raw cache entry:

go run ./cmd/browsertools capture chromium \
--url https://example.test/member \
--allow-origin https://example.test \
--cache-root ./.browsertools-cache \
--action-hint read_dashboard \
--retain-for 24h

The command blocks non-GET/HEAD requests, unapproved origins, child frames, service workers, WebSockets, popups, downloads, dialogs, file choosers, and non-essential resources. It uses finite navigation, total, request, response, ARIA-depth, evidence-size, and retention limits. Only cache metadata is printed; raw ARIA/JSON-LD content is never written to stdout. See Safe live capture for the review/redaction handoff.

Explicit private screenshots, traces, and minimal-content HAR can be captured as one short-lived, non-publishable ZIP:

go run ./cmd/browsertools rich-capture chromium \
--url https://example.test/member \
--allow-origin https://example.test \
--cache-root ./.browsertools-cache \
--artifact screenshot --artifact trace --artifact har \
--retain-for 1h

The command prints only cache metadata. Export requires a new 0600 file; review for secrets is mandatory, and cache delete requires the exact digest twice. Rich artifacts have no publication or normalized-evidence path.

After normalization, the terminal guide makes every capability and safety decision explicit and emits one deterministic envelope containing the accepted spec, generated profile, action-bound evidence, ambiguity decisions, and promotable review:

go run ./cmd/browsertools guide author \
--evidence ./evidence.json \
--at 2026-08-16T12:00:00Z \
--out ./guided-authoring.json

A separately selected live check can compare declared locators, waits, and output shapes with the current page without executing any profile macro or emitting page values:

go run ./cmd/browsertools live-check chromium \
--profile ./profile.yaml \
--url https://example.test/member \
--allow-origin https://example.test \
--action read_dashboard \
--at 2026-08-16T12:00:00Z \
--out ./live-check.json

Both paths keep sequence intent, side effects, confirmation, expiry, and ambiguity decisions human-authored. The live check reuses the exact-origin ephemeral capture policy, accepts plain CSS outputs but no Playwright selector language, and writes only profile-bound match/type facts. See Guided capability authoring and live checks.

The same profile-derived read-only checks can be compared without locator rewrites across explicitly installed engines:

go run ./cmd/browsertools portability check \
--profile ./profile.yaml \
--url https://example.test/member \
--allow-origin https://example.test \
--action read_dashboard \
--engine chromium --engine firefox --engine webkit \
--out ./portability.json

Chromium is the required baseline. Missing engines and shape differences are fixed value-free diagnostics, not silent fallbacks. See Private rich evidence and cross-engine portability.

Portable sign-in recipes use a separate additive contract and remain local to the workflow package:

go run ./cmd/browsertools auth-draft build \
--spec ./authentication-spec.yaml \
--out ./browser-authentication/member.yaml
go run ./cmd/browsertools auth-profile validate \
--input ./browser-authentication/member.yaml \
--at 2026-08-16T00:00:00Z
go run ./cmd/browsertools auth-review bundle \
--profile ./browser-authentication/member.yaml \
--at 2026-08-16T00:00:00Z \
--out ./browser-authentication/member.review.json

An explicit headed authoring command can then observe the exact recipe while the operator enters credentials and completes MFA directly in the browser:

go run ./cmd/browsertools auth-assist chromium \
--profile ./browser-authentication/member.yaml \
--flow member_login_push \
--approve-origin https://members.example.test \
--approve-origin https://login.example.test \
--post-budget member_login_push:3=2 \
--out ./browser-authentication/member.assisted.json

The profile supplies every locator, challenge alternative, submit step, and success condition; Browsertools does not infer them. Each selected flow runs in a separate visible ephemeral context. Browsertools navigates declared URLs and counts declared accessibility locators, but the operator performs every credential, click, and challenge step and signals completion with an empty terminal line. A POST is blocked unless its exact zero-based flow step has an explicit bounded --post-budget; all other mutating methods are blocked.

The 0600 output is created only after every context has closed and contains a selected uws.browser-authentication.1.0 profile, its digest-bound review, and value-free origin/count/request evidence. It cannot use stdin for a profile, stdout for the artifact, or overwrite a path. Authentication recipes are also excluded from static registry publication. Actual credentials, MFA responses, OAuth state, cookies, storage, and sessions stay in the browser or downstream private runtime. See Browser authentication profiles.

Account registration uses a separate explicitly mutating contract. Browsertools can validate, deterministically build, and digest-review only the inert recipe:

go run ./cmd/browsertools registration-draft build \
--spec ./registration-spec.yaml \
--out ./browser-registration/dedicated-test-user.yaml
go run ./cmd/browsertools registration-profile validate \
--input ./browser-registration/dedicated-test-user.yaml \
--at 2026-08-25T00:00:00Z
go run ./cmd/browsertools registration-review bundle \
--profile ./browser-registration/dedicated-test-user.yaml \
--at 2026-08-25T00:00:00Z \
--out ./browser-registration/dedicated-test-user.review.json

These commands are file-only and never launch a browser, contact a target, resolve a symbolic credential, submit a registration, handle CAPTCHA/MFA/email verification, approve a run, or perform cleanup. Registration profiles and reviews remain package-local and are excluded from the browser capability registry. See Browser registration profiles.

The typed registrationauthor.Build path combines one current reduced registration observation with a complete registrationdraft.Spec, exact reviewed candidate IDs, selected submit candidate and flow, approved origins, and explicit fixed call controls. It reconstructs the current-generation candidate IDs, binds the one accessibility-name submit, and emits the exact M26 review message without inferring any profile or cleanup field. After clean session teardown, registrationauthorresult.FinalizePrivate independently reconstructs and strict-decodes the M26 result before and after an anchored owner-only, create-once write; its path remains process-private.

The standalone producer uses that complete path:

browsertools registration-author-session chromium \
--private-root ./private-registration-results \
--driver-dir "$PLAYWRIGHT_DRIVER_PATH"

Stdin and stdout are reserved for registration author-session NDJSON. The worker defaults to v1; --protocol v2 deliberately selects the additive retained-query contract and guarded Chromium routing. The private root must already be a mode-0700 directory. The command never prints the resulting file name or digest, and it provides no registration runtime or submit command.

Caller-supplied raw captures and derived artifacts can be kept in an explicit private local cache. Raw entries can never be publication eligible:

go run ./cmd/browsertools cache put \
--root ./.browsertools-cache --input ./capture.json \
--kind private_raw --media-type application/json \
--created-at 2026-08-14T00:00:00Z
go run ./cmd/browsertools cache list \
--root ./.browsertools-cache --at 2026-08-14T12:00:00Z
go run ./cmd/browsertools cache prune \
--root ./.browsertools-cache --at 2026-09-14T00:00:00Z
go run ./cmd/browsertools cache delete \
--root ./.browsertools-cache --id sha256:EXACT_ID --confirm-id sha256:EXACT_ID

What It Owns

  • A complete typed model and validation helpers for UWS browser-profile documents.
  • Typed validation, deterministic drafting, digest-bound review, freshness, and local discovery for package-local uws.browser-authentication.1.0 recipes.
  • Typed offline validation, deterministic explicit drafting, digest-bound review, and freshness for package-local uws.browser-registration.1.0 recipes.
  • Secret-free evidence records from browser and scraper tooling.
  • Draft profile generation from reviewed evidence.
  • Review bundles with validation, confidence, expiry, side-effect, and revalidation notes.
  • Deterministic fixture-only revalidation and digest-bound promotion gates.
  • A bounded, content-addressed private cache for caller-supplied experiences, normalized evidence, profiles, and review bundles.
  • Canonical, digest-bound, lifecycle-assessed publication bundles for reviewed profiles, safe evidence, and optional inert UWS companions.
  • A service-free static registry layout, atomic local publisher, bounded local/HTTPS reader, and local browser-source discovery report.
  • Browser-profile, scraper/crawler, and browser-backed wrapper examples.
  • Optional adapters for Playwright, llm-scraper, Crawl4AI, and Firecrawl outputs.
  • An isolated Playwright-Go acquisition boundary, pinned capability policy, and offline installation doctor for authoring-only browser tooling.
  • Explicit headless Chromium acquisition into the private raw cache with exact origins, ephemeral context destruction, and closed activity/resource bounds.
  • Deterministic terminal-guided authoring that binds explicit intent, reviewed evidence, decisions, a valid profile, and a promotable review.
  • Value-free Chromium live checks for declared locators, waits, and output shapes without macro execution.
  • Explicit short-lived screenshot/trace/HAR bundles with mandatory secret review, no publication path, and exact-ID deletion.
  • Fresh Chromium-baseline Firefox/WebKit comparisons of the same value-free profile probes, plus documented browser.1.6 contract pressure.
  • Headed manual authentication observation with separate ephemeral contexts, exact preapproved origins, step-scoped POST ceilings, and local value-free draft/review bundles.

What It Does Not Own

  • UWS schema and workflow semantics. Those live in github.com/OpenUdon/uws.
  • OpenAPI/API-source discovery and provider catalog metadata. Those belong in github.com/OpenUdon/apitools.
  • Production browser execution, runtime credential resolution, retained cookies/sessions, retries, account selection, or production side effects.
  • A general Playwright, WebDriver, Puppeteer, or scraping DSL.
  • Implicit browser launch or uploading cached content. Acquisition commands are separately selected; cache commands are local and offline, and publication has a separate verification boundary.
  • Accounts, membership, a registry database, remote writes, or deployment credentials. Static catalogs are reviewed and deployed by existing repository/hosting workflows.
  • Publication of authentication recipes through the static browser capability registry.
  • Publication of registration recipes through the static browser capability registry, or live registration/account cleanup of any kind.

Why Not Just OpenAPI?

OpenAPI should describe a stable HTTP service. If you build a browser-backed wrapper service, OpenAPI should describe that wrapper. Browsertools can also emit an advisory overlay sidecar for the wrapper, linking OpenAPI operations to reviewed browser-profile actions and review bundles.

browser-profile describes the UI binding behind the wrapper or behind a UWS browser operation:

website UI
-> browsertools-reviewed profile
-> browser runtime executes profile

or:

website UI
-> browser-backed wrapper service
-> OpenAPI describes wrapper
-> UWS binds to wrapper API

Documentation

Development

go test ./...
go vet ./...
GOWORK=off go run golang.org/x/vuln/cmd/govulncheck@v1.6.0 ./...
git diff --check
(cd ../uws && go test ./...)

Default tests use fakes and synthetic fixtures; they do not install or launch browsers and do not contact the network.

An installed-browser loopback integration test is opt-in:

BROWSERTOOLS_LIVE_TEST=1 go test ./capture -run PlaywrightLiveCaptureLoopback

Headed authentication behavior is covered by browser-free policy/state-machine tests by default. A real site is never contacted by the test suite. An installed-browser headed smoke test is separately opt-in and loopback-only:

BROWSERTOOLS_AUTH_LIVE_TEST=1 go test ./capture -run PlaywrightAuthHeadedLoopback

Rich evidence and cross-engine smoke tests are independently gated and remain loopback-only:

BROWSERTOOLS_RICH_LIVE_TEST=1 go test ./capture -run PlaywrightRichCaptureLoopback
BROWSERTOOLS_PORTABILITY_LIVE_TEST=1 go test ./capture -run PlaywrightPortabilityLoopback

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - OpenUdon/browsertools · GitHub
Skip to content

Latest commit

History

72 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

browsertools

browsertools is OpenUdon's tooling project for turning real website UI evidence into reviewed UWS browser capability profiles.

It exists for the gap where a task is exposed through a web UI and no suitable API source document is available. The output is not a browser command trace and not an OpenAPI substitute. The output is a portable, reviewed browser-profile document that a UWS workflow can bind to.

real website UI
-> browsertools using Playwright / llm-scraper / Crawl4AI / Firecrawl
-> reviewed browser-profile
-> UWS operation binds to browser-profile action

Where Browsertools Fits

OpenUdon's iCoT is the primary end-user authoring entry point across API, browser, and runtime-handoff sources. iCoT retains goal interviewing, LLM/human interaction, source selection, and package staging. For UI-only acquisition, the distributed icot executable re-executes a private copy of itself as a separate process using Browsertools' importable worker; an external browsertools CLI remains available for experts and maintainers.

Browsertools owns Playwright-based acquisition, browser safety policy, profile synthesis, and the shared validation library for browser capability and authentication profiles, plus offline validation/draft/review tooling for the separate UWS browser-registration profile. Its CLI is primarily a machine- facing protocol plus maintainer and offline tooling, not a parallel end-user authoring product. Browsertools is not the production runtime; runtime replay belongs to Udon and Browserdriver. See the canonical OpenUdon integration reference for the two integration paths and full ownership split.

For UWS 1.9.1 advisory integrity analysis, package github.com/OpenUdon/browsertools/contenttrust builds a resolver from reviewed profiles keyed by sourceDescription name. Browser-derived outputs default to untrusted while retaining their declared value shape. Navigation and option selection parameters are authority-bearing, confirmation prompts are instructions, and typed text remains data. The resolver performs no browser work and never changes validation or execution.

Authenticated live authoring uses the strict browsertools.author-session.v2 NDJSON boundary. Human-reviewed MFA kinds and up to 16 final accessibility outputs produce one private browsertools.authenticated-authoring.v2 envelope; the protocol carries no credential, page value, cookie, or browser state. See Authenticated goal-directed browser authoring.

Registration authoring has separate browser-independent contracts. V1 (browsertools.registration-author-session.v1 and private browsertools.registration-authoring.v1) remains query-free. Additive v2 (browsertools.registration-author-session.v2 and private browsertools.registration-authoring.v2) admits only bounded canonical literal structural queries and validates them on all session and retained BRP navigations. Both continue only approved-origin GET/HEAD traffic and bind one reviewed inert BRP without claiming a submit, account attempt, session, or supported runtime. Canonical unapproved non-navigation GET/HEAD subresources are counted and aborted before contact without expanding the allowlist or poisoning an otherwise clean observation; unsafe navigation, methods, and persistent channels remain fatal. A guarded typed Chromium backend and deterministic explicit candidate builder implement those contracts. The importable registrationauthorworker and browsertools registration-author-session chromium expose that backend through the same closed no-submit wire and finalize the result only under an explicit owner-only private root. See Browser registration profiles.

Page-controlled frame names cross the same canonical reduction boundary as candidate labels. Exact backend-reported MFA subsets are preserved, and the finite total timeout charges browser work rather than human credential/MFA wait time.

The authorworker package is the supported process-entry adapter for browsertools author-session chromium and the hidden iCoT worker. It accepts context, private root, optional driver directory, interruptible owned stdin, and stdout. SIGINT/SIGTERM or parent cancellation closes protocol input, then waits for browser teardown; failed close negotiation or teardown exits nonzero. Embedding it does not move Playwright into the iCoT engine or HTTP server process.

The separate registrationauthorworker is the supported process entry for no-submit BRP production. It performs read-only pinned-driver preflight, owns the closeable NDJSON input and headed browser lifetime, and creates an independently reconstructed result only after clean teardown. Its API and CLI return no result path or digest. A re-executing parent owns executable hashing, minimal child environment, and process-group termination. On Linux, an administrator-provisioned CHROME_DEVEL_SANDBOX is forwarded to Chromium only after exact mode, root ownership, link count, setuid-filesystem, resolved-path, and complete ancestor-control checks; sandbox disabling is never supported.

Accessibility-label reduction is a useful heuristic, not data loss prevention. Ordinary names, identifiers, and order numbers can remain in reduced observations and reviewed traces. Operators must review those records before retaining or sharing them.

Quick Start

go get github.com/OpenUdon/browsertools

The full pipeline from evidence to a reviewable bundle:

import (
"time""github.com/OpenUdon/browsertools/adapter""github.com/OpenUdon/browsertools/adapter/playwright""github.com/OpenUdon/browsertools/bundle""github.com/OpenUdon/browsertools/draft""github.com/OpenUdon/browsertools/evidence""github.com/OpenUdon/browsertools/profile""github.com/OpenUdon/browsertools/review"
)
// 1. Import saved Playwright snapshot as normalized evidence.a:=&playwright.Adapter{}
records, err:=a.Import(snapshotJSON, adapter.Options{
Origin: "https://example.test",
ActionHint: "read_status",
RedactionStatus: evidence.RedactionNotRequired,
})
// 2. Add explicit action intent. Evidence never invents a click or assumes// that an action is read-only.result, err:=draft.Build(records, draft.Spec{
Info: profile.Info{Title: "Example", Origin: profile.Origins{"https://example.test"}},
ObservationKind: profile.ObservationAccessibilitySnapshot,
Confidence: profile.ConfidenceMedium,
ExpiresAfter: "P30D",
Actions: map[string]draft.ActionSpec{
"read_status": {
Sequence: []profile.Step{
{Kind: profile.StepNavigate, Navigate: "/status"},
{Kind: profile.StepWaitFor, WaitFor: &profile.WaitForCondition{
Locator: &profile.Locator{Role: profile.RoleStatus, Name: "OK"},
}},
},
SideEffects: []profile.SideEffect{profile.SideEffectReadOnly},
ConfirmationPolicy: profile.ConfirmationPolicy{Required: false},
},
},
})
// 3. Build a digest-bound bundle at an explicit assessment time.assessedAt:=time.Now().UTC()
reviewed, err:=review.Build(result.Profile, records, result.Decisions, assessedAt)
iferr!=nil||!reviewed.Promotable() {
// fix gaps before promoting
}
// 4. Wrap the exact reviewed inputs in an inert publication bundle.published, err:=bundle.Build(bundle.BuildOptions{
ID: "example/status", Release: "1.0.0", Source: "reviewed_fixture",
License: "CC0-1.0", Profile: result.Profile, Review: reviewed,
Evidence: records, PublishedAt: assessedAt,
})

The CLI exposes the same offline pipeline:

go run ./cmd/browsertools profile validate --input ./profiles/example.yaml
go run ./cmd/browsertools evidence import \
--adapter playwright --input ./capture.json \
--origin https://example.test --redaction-status not_required \
--out ./evidence.json
go run ./cmd/browsertools draft build \
--evidence ./evidence.json --spec ./draft-spec.yaml \
--out ./profile.yaml
go run ./cmd/browsertools review bundle \
--profile ./profile.yaml --evidence ./evidence.json \
--at 2026-08-14T00:00:00Z --out ./review-bundle.json
go run ./cmd/browsertools revalidate check \
--profile ./profile.yaml --evidence ./evidence.json \
--at 2026-08-14T00:00:00Z --out ./revalidation.json
go run ./cmd/browsertools bundle build \
--id example/status --release 1.0.0 \
--profile ./profile.yaml --review ./review-bundle.json \
--evidence ./evidence.json --source reviewed_fixture --license CC0-1.0 \
--published-at 2026-08-14T00:00:00Z --out ./capability-bundle.json
go run ./cmd/browsertools bundle verify \
--input ./capability-bundle.json --at 2026-08-14T00:00:00Z
go run ./cmd/browsertools registry publish \
--root ./public-registry --bundle ./capability-bundle.json \
--at 2026-08-14T00:00:00Z
go run ./cmd/browsertools registry search \
--location ./public-registry --query status \
--at 2026-08-14T00:00:00Z

Browser acquisition is an explicit, separately installed authoring feature. Browsertools pins Playwright-Go v0.6201.0 (Playwright 1.62.1). Install the matching driver and Chromium deliberately, then verify the local installation:

go run github.com/mxschmitt/playwright-go/cmd/playwright@v0.6201.0 install chromium
go run ./cmd/browsertools playwright doctor --engine chromium

Before playwright doctor or an author session starts, Browsertools verifies the installed Node executable, CLI, and exact Playwright 1.62.1 package using read-only filesystem checks. It creates no cache directory, invokes no installer, and contacts no network. The doctor then starts and stops only that installed driver; its full local CLI report may include the browser executable path, while the separate UI-safe report omits executable and private paths. It does not contact a site or launch a browser. The other CLI commands remain file-first unless they are explicitly named live acquisition, check, or assisted-authentication commands.

Safe live capture is Chromium-only, headless, non-interactive, and private. It requires every exact origin and writes page material only to a finite-retention private_raw cache entry:

go run ./cmd/browsertools capture chromium \
--url https://example.test/member \
--allow-origin https://example.test \
--cache-root ./.browsertools-cache \
--action-hint read_dashboard \
--retain-for 24h

The command blocks non-GET/HEAD requests, unapproved origins, child frames, service workers, WebSockets, popups, downloads, dialogs, file choosers, and non-essential resources. It uses finite navigation, total, request, response, ARIA-depth, evidence-size, and retention limits. Only cache metadata is printed; raw ARIA/JSON-LD content is never written to stdout. See Safe live capture for the review/redaction handoff.

Explicit private screenshots, traces, and minimal-content HAR can be captured as one short-lived, non-publishable ZIP:

go run ./cmd/browsertools rich-capture chromium \
--url https://example.test/member \
--allow-origin https://example.test \
--cache-root ./.browsertools-cache \
--artifact screenshot --artifact trace --artifact har \
--retain-for 1h

The command prints only cache metadata. Export requires a new 0600 file; review for secrets is mandatory, and cache delete requires the exact digest twice. Rich artifacts have no publication or normalized-evidence path.

After normalization, the terminal guide makes every capability and safety decision explicit and emits one deterministic envelope containing the accepted spec, generated profile, action-bound evidence, ambiguity decisions, and promotable review:

go run ./cmd/browsertools guide author \
--evidence ./evidence.json \
--at 2026-08-16T12:00:00Z \
--out ./guided-authoring.json

A separately selected live check can compare declared locators, waits, and output shapes with the current page without executing any profile macro or emitting page values:

go run ./cmd/browsertools live-check chromium \
--profile ./profile.yaml \
--url https://example.test/member \
--allow-origin https://example.test \
--action read_dashboard \
--at 2026-08-16T12:00:00Z \
--out ./live-check.json

Both paths keep sequence intent, side effects, confirmation, expiry, and ambiguity decisions human-authored. The live check reuses the exact-origin ephemeral capture policy, accepts plain CSS outputs but no Playwright selector language, and writes only profile-bound match/type facts. See Guided capability authoring and live checks.

The same profile-derived read-only checks can be compared without locator rewrites across explicitly installed engines:

go run ./cmd/browsertools portability check \
--profile ./profile.yaml \
--url https://example.test/member \
--allow-origin https://example.test \
--action read_dashboard \
--engine chromium --engine firefox --engine webkit \
--out ./portability.json

Chromium is the required baseline. Missing engines and shape differences are fixed value-free diagnostics, not silent fallbacks. See Private rich evidence and cross-engine portability.

Portable sign-in recipes use a separate additive contract and remain local to the workflow package:

go run ./cmd/browsertools auth-draft build \
--spec ./authentication-spec.yaml \
--out ./browser-authentication/member.yaml
go run ./cmd/browsertools auth-profile validate \
--input ./browser-authentication/member.yaml \
--at 2026-08-16T00:00:00Z
go run ./cmd/browsertools auth-review bundle \
--profile ./browser-authentication/member.yaml \
--at 2026-08-16T00:00:00Z \
--out ./browser-authentication/member.review.json

An explicit headed authoring command can then observe the exact recipe while the operator enters credentials and completes MFA directly in the browser:

go run ./cmd/browsertools auth-assist chromium \
--profile ./browser-authentication/member.yaml \
--flow member_login_push \
--approve-origin https://members.example.test \
--approve-origin https://login.example.test \
--post-budget member_login_push:3=2 \
--out ./browser-authentication/member.assisted.json

The profile supplies every locator, challenge alternative, submit step, and success condition; Browsertools does not infer them. Each selected flow runs in a separate visible ephemeral context. Browsertools navigates declared URLs and counts declared accessibility locators, but the operator performs every credential, click, and challenge step and signals completion with an empty terminal line. A POST is blocked unless its exact zero-based flow step has an explicit bounded --post-budget; all other mutating methods are blocked.

The 0600 output is created only after every context has closed and contains a selected uws.browser-authentication.1.0 profile, its digest-bound review, and value-free origin/count/request evidence. It cannot use stdin for a profile, stdout for the artifact, or overwrite a path. Authentication recipes are also excluded from static registry publication. Actual credentials, MFA responses, OAuth state, cookies, storage, and sessions stay in the browser or downstream private runtime. See Browser authentication profiles.

Account registration uses a separate explicitly mutating contract. Browsertools can validate, deterministically build, and digest-review only the inert recipe:

go run ./cmd/browsertools registration-draft build \
--spec ./registration-spec.yaml \
--out ./browser-registration/dedicated-test-user.yaml
go run ./cmd/browsertools registration-profile validate \
--input ./browser-registration/dedicated-test-user.yaml \
--at 2026-08-25T00:00:00Z
go run ./cmd/browsertools registration-review bundle \
--profile ./browser-registration/dedicated-test-user.yaml \
--at 2026-08-25T00:00:00Z \
--out ./browser-registration/dedicated-test-user.review.json

These commands are file-only and never launch a browser, contact a target, resolve a symbolic credential, submit a registration, handle CAPTCHA/MFA/email verification, approve a run, or perform cleanup. Registration profiles and reviews remain package-local and are excluded from the browser capability registry. See Browser registration profiles.

The typed registrationauthor.Build path combines one current reduced registration observation with a complete registrationdraft.Spec, exact reviewed candidate IDs, selected submit candidate and flow, approved origins, and explicit fixed call controls. It reconstructs the current-generation candidate IDs, binds the one accessibility-name submit, and emits the exact M26 review message without inferring any profile or cleanup field. After clean session teardown, registrationauthorresult.FinalizePrivate independently reconstructs and strict-decodes the M26 result before and after an anchored owner-only, create-once write; its path remains process-private.

The standalone producer uses that complete path:

browsertools registration-author-session chromium \
--private-root ./private-registration-results \
--driver-dir "$PLAYWRIGHT_DRIVER_PATH"

Stdin and stdout are reserved for registration author-session NDJSON. The worker defaults to v1; --protocol v2 deliberately selects the additive retained-query contract and guarded Chromium routing. The private root must already be a mode-0700 directory. The command never prints the resulting file name or digest, and it provides no registration runtime or submit command.

Caller-supplied raw captures and derived artifacts can be kept in an explicit private local cache. Raw entries can never be publication eligible:

go run ./cmd/browsertools cache put \
--root ./.browsertools-cache --input ./capture.json \
--kind private_raw --media-type application/json \
--created-at 2026-08-14T00:00:00Z
go run ./cmd/browsertools cache list \
--root ./.browsertools-cache --at 2026-08-14T12:00:00Z
go run ./cmd/browsertools cache prune \
--root ./.browsertools-cache --at 2026-09-14T00:00:00Z
go run ./cmd/browsertools cache delete \
--root ./.browsertools-cache --id sha256:EXACT_ID --confirm-id sha256:EXACT_ID

What It Owns

  • A complete typed model and validation helpers for UWS browser-profile documents.
  • Typed validation, deterministic drafting, digest-bound review, freshness, and local discovery for package-local uws.browser-authentication.1.0 recipes.
  • Typed offline validation, deterministic explicit drafting, digest-bound review, and freshness for package-local uws.browser-registration.1.0 recipes.
  • Secret-free evidence records from browser and scraper tooling.
  • Draft profile generation from reviewed evidence.
  • Review bundles with validation, confidence, expiry, side-effect, and revalidation notes.
  • Deterministic fixture-only revalidation and digest-bound promotion gates.
  • A bounded, content-addressed private cache for caller-supplied experiences, normalized evidence, profiles, and review bundles.
  • Canonical, digest-bound, lifecycle-assessed publication bundles for reviewed profiles, safe evidence, and optional inert UWS companions.
  • A service-free static registry layout, atomic local publisher, bounded local/HTTPS reader, and local browser-source discovery report.
  • Browser-profile, scraper/crawler, and browser-backed wrapper examples.
  • Optional adapters for Playwright, llm-scraper, Crawl4AI, and Firecrawl outputs.
  • An isolated Playwright-Go acquisition boundary, pinned capability policy, and offline installation doctor for authoring-only browser tooling.
  • Explicit headless Chromium acquisition into the private raw cache with exact origins, ephemeral context destruction, and closed activity/resource bounds.
  • Deterministic terminal-guided authoring that binds explicit intent, reviewed evidence, decisions, a valid profile, and a promotable review.
  • Value-free Chromium live checks for declared locators, waits, and output shapes without macro execution.
  • Explicit short-lived screenshot/trace/HAR bundles with mandatory secret review, no publication path, and exact-ID deletion.
  • Fresh Chromium-baseline Firefox/WebKit comparisons of the same value-free profile probes, plus documented browser.1.6 contract pressure.
  • Headed manual authentication observation with separate ephemeral contexts, exact preapproved origins, step-scoped POST ceilings, and local value-free draft/review bundles.

What It Does Not Own

  • UWS schema and workflow semantics. Those live in github.com/OpenUdon/uws.
  • OpenAPI/API-source discovery and provider catalog metadata. Those belong in github.com/OpenUdon/apitools.
  • Production browser execution, runtime credential resolution, retained cookies/sessions, retries, account selection, or production side effects.
  • A general Playwright, WebDriver, Puppeteer, or scraping DSL.
  • Implicit browser launch or uploading cached content. Acquisition commands are separately selected; cache commands are local and offline, and publication has a separate verification boundary.
  • Accounts, membership, a registry database, remote writes, or deployment credentials. Static catalogs are reviewed and deployed by existing repository/hosting workflows.
  • Publication of authentication recipes through the static browser capability registry.
  • Publication of registration recipes through the static browser capability registry, or live registration/account cleanup of any kind.

Why Not Just OpenAPI?

OpenAPI should describe a stable HTTP service. If you build a browser-backed wrapper service, OpenAPI should describe that wrapper. Browsertools can also emit an advisory overlay sidecar for the wrapper, linking OpenAPI operations to reviewed browser-profile actions and review bundles.

browser-profile describes the UI binding behind the wrapper or behind a UWS browser operation:

website UI
-> browsertools-reviewed profile
-> browser runtime executes profile

or:

website UI
-> browser-backed wrapper service
-> OpenAPI describes wrapper
-> UWS binds to wrapper API

Documentation

Development

go test ./...
go vet ./...
GOWORK=off go run golang.org/x/vuln/cmd/govulncheck@v1.6.0 ./...
git diff --check
(cd ../uws && go test ./...)

Default tests use fakes and synthetic fixtures; they do not install or launch browsers and do not contact the network.

An installed-browser loopback integration test is opt-in:

BROWSERTOOLS_LIVE_TEST=1 go test ./capture -run PlaywrightLiveCaptureLoopback

Headed authentication behavior is covered by browser-free policy/state-machine tests by default. A real site is never contacted by the test suite. An installed-browser headed smoke test is separately opt-in and loopback-only:

BROWSERTOOLS_AUTH_LIVE_TEST=1 go test ./capture -run PlaywrightAuthHeadedLoopback

Rich evidence and cross-engine smoke tests are independently gated and remain loopback-only:

BROWSERTOOLS_RICH_LIVE_TEST=1 go test ./capture -run PlaywrightRichCaptureLoopback
BROWSERTOOLS_PORTABILITY_LIVE_TEST=1 go test ./capture -run PlaywrightPortabilityLoopback

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - OpenUdon/browsertools · GitHub
Skip to content

Latest commit

History

72 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

browsertools

browsertools is OpenUdon's tooling project for turning real website UI evidence into reviewed UWS browser capability profiles.

It exists for the gap where a task is exposed through a web UI and no suitable API source document is available. The output is not a browser command trace and not an OpenAPI substitute. The output is a portable, reviewed browser-profile document that a UWS workflow can bind to.

real website UI
-> browsertools using Playwright / llm-scraper / Crawl4AI / Firecrawl
-> reviewed browser-profile
-> UWS operation binds to browser-profile action

Where Browsertools Fits

OpenUdon's iCoT is the primary end-user authoring entry point across API, browser, and runtime-handoff sources. iCoT retains goal interviewing, LLM/human interaction, source selection, and package staging. For UI-only acquisition, the distributed icot executable re-executes a private copy of itself as a separate process using Browsertools' importable worker; an external browsertools CLI remains available for experts and maintainers.

Browsertools owns Playwright-based acquisition, browser safety policy, profile synthesis, and the shared validation library for browser capability and authentication profiles, plus offline validation/draft/review tooling for the separate UWS browser-registration profile. Its CLI is primarily a machine- facing protocol plus maintainer and offline tooling, not a parallel end-user authoring product. Browsertools is not the production runtime; runtime replay belongs to Udon and Browserdriver. See the canonical OpenUdon integration reference for the two integration paths and full ownership split.

For UWS 1.9.1 advisory integrity analysis, package github.com/OpenUdon/browsertools/contenttrust builds a resolver from reviewed profiles keyed by sourceDescription name. Browser-derived outputs default to untrusted while retaining their declared value shape. Navigation and option selection parameters are authority-bearing, confirmation prompts are instructions, and typed text remains data. The resolver performs no browser work and never changes validation or execution.

Authenticated live authoring uses the strict browsertools.author-session.v2 NDJSON boundary. Human-reviewed MFA kinds and up to 16 final accessibility outputs produce one private browsertools.authenticated-authoring.v2 envelope; the protocol carries no credential, page value, cookie, or browser state. See Authenticated goal-directed browser authoring.

Registration authoring has separate browser-independent contracts. V1 (browsertools.registration-author-session.v1 and private browsertools.registration-authoring.v1) remains query-free. Additive v2 (browsertools.registration-author-session.v2 and private browsertools.registration-authoring.v2) admits only bounded canonical literal structural queries and validates them on all session and retained BRP navigations. Both continue only approved-origin GET/HEAD traffic and bind one reviewed inert BRP without claiming a submit, account attempt, session, or supported runtime. Canonical unapproved non-navigation GET/HEAD subresources are counted and aborted before contact without expanding the allowlist or poisoning an otherwise clean observation; unsafe navigation, methods, and persistent channels remain fatal. A guarded typed Chromium backend and deterministic explicit candidate builder implement those contracts. The importable registrationauthorworker and browsertools registration-author-session chromium expose that backend through the same closed no-submit wire and finalize the result only under an explicit owner-only private root. See Browser registration profiles.

Page-controlled frame names cross the same canonical reduction boundary as candidate labels. Exact backend-reported MFA subsets are preserved, and the finite total timeout charges browser work rather than human credential/MFA wait time.

The authorworker package is the supported process-entry adapter for browsertools author-session chromium and the hidden iCoT worker. It accepts context, private root, optional driver directory, interruptible owned stdin, and stdout. SIGINT/SIGTERM or parent cancellation closes protocol input, then waits for browser teardown; failed close negotiation or teardown exits nonzero. Embedding it does not move Playwright into the iCoT engine or HTTP server process.

The separate registrationauthorworker is the supported process entry for no-submit BRP production. It performs read-only pinned-driver preflight, owns the closeable NDJSON input and headed browser lifetime, and creates an independently reconstructed result only after clean teardown. Its API and CLI return no result path or digest. A re-executing parent owns executable hashing, minimal child environment, and process-group termination. On Linux, an administrator-provisioned CHROME_DEVEL_SANDBOX is forwarded to Chromium only after exact mode, root ownership, link count, setuid-filesystem, resolved-path, and complete ancestor-control checks; sandbox disabling is never supported.

Accessibility-label reduction is a useful heuristic, not data loss prevention. Ordinary names, identifiers, and order numbers can remain in reduced observations and reviewed traces. Operators must review those records before retaining or sharing them.

Quick Start

go get github.com/OpenUdon/browsertools

The full pipeline from evidence to a reviewable bundle:

import (
"time""github.com/OpenUdon/browsertools/adapter""github.com/OpenUdon/browsertools/adapter/playwright""github.com/OpenUdon/browsertools/bundle""github.com/OpenUdon/browsertools/draft""github.com/OpenUdon/browsertools/evidence""github.com/OpenUdon/browsertools/profile""github.com/OpenUdon/browsertools/review"
)
// 1. Import saved Playwright snapshot as normalized evidence.a:=&playwright.Adapter{}
records, err:=a.Import(snapshotJSON, adapter.Options{
Origin: "https://example.test",
ActionHint: "read_status",
RedactionStatus: evidence.RedactionNotRequired,
})
// 2. Add explicit action intent. Evidence never invents a click or assumes// that an action is read-only.result, err:=draft.Build(records, draft.Spec{
Info: profile.Info{Title: "Example", Origin: profile.Origins{"https://example.test"}},
ObservationKind: profile.ObservationAccessibilitySnapshot,
Confidence: profile.ConfidenceMedium,
ExpiresAfter: "P30D",
Actions: map[string]draft.ActionSpec{
"read_status": {
Sequence: []profile.Step{
{Kind: profile.StepNavigate, Navigate: "/status"},
{Kind: profile.StepWaitFor, WaitFor: &profile.WaitForCondition{
Locator: &profile.Locator{Role: profile.RoleStatus, Name: "OK"},
}},
},
SideEffects: []profile.SideEffect{profile.SideEffectReadOnly},
ConfirmationPolicy: profile.ConfirmationPolicy{Required: false},
},
},
})
// 3. Build a digest-bound bundle at an explicit assessment time.assessedAt:=time.Now().UTC()
reviewed, err:=review.Build(result.Profile, records, result.Decisions, assessedAt)
iferr!=nil||!reviewed.Promotable() {
// fix gaps before promoting
}
// 4. Wrap the exact reviewed inputs in an inert publication bundle.published, err:=bundle.Build(bundle.BuildOptions{
ID: "example/status", Release: "1.0.0", Source: "reviewed_fixture",
License: "CC0-1.0", Profile: result.Profile, Review: reviewed,
Evidence: records, PublishedAt: assessedAt,
})

The CLI exposes the same offline pipeline:

go run ./cmd/browsertools profile validate --input ./profiles/example.yaml
go run ./cmd/browsertools evidence import \
--adapter playwright --input ./capture.json \
--origin https://example.test --redaction-status not_required \
--out ./evidence.json
go run ./cmd/browsertools draft build \
--evidence ./evidence.json --spec ./draft-spec.yaml \
--out ./profile.yaml
go run ./cmd/browsertools review bundle \
--profile ./profile.yaml --evidence ./evidence.json \
--at 2026-08-14T00:00:00Z --out ./review-bundle.json
go run ./cmd/browsertools revalidate check \
--profile ./profile.yaml --evidence ./evidence.json \
--at 2026-08-14T00:00:00Z --out ./revalidation.json
go run ./cmd/browsertools bundle build \
--id example/status --release 1.0.0 \
--profile ./profile.yaml --review ./review-bundle.json \
--evidence ./evidence.json --source reviewed_fixture --license CC0-1.0 \
--published-at 2026-08-14T00:00:00Z --out ./capability-bundle.json
go run ./cmd/browsertools bundle verify \
--input ./capability-bundle.json --at 2026-08-14T00:00:00Z
go run ./cmd/browsertools registry publish \
--root ./public-registry --bundle ./capability-bundle.json \
--at 2026-08-14T00:00:00Z
go run ./cmd/browsertools registry search \
--location ./public-registry --query status \
--at 2026-08-14T00:00:00Z

Browser acquisition is an explicit, separately installed authoring feature. Browsertools pins Playwright-Go v0.6201.0 (Playwright 1.62.1). Install the matching driver and Chromium deliberately, then verify the local installation:

go run github.com/mxschmitt/playwright-go/cmd/playwright@v0.6201.0 install chromium
go run ./cmd/browsertools playwright doctor --engine chromium

Before playwright doctor or an author session starts, Browsertools verifies the installed Node executable, CLI, and exact Playwright 1.62.1 package using read-only filesystem checks. It creates no cache directory, invokes no installer, and contacts no network. The doctor then starts and stops only that installed driver; its full local CLI report may include the browser executable path, while the separate UI-safe report omits executable and private paths. It does not contact a site or launch a browser. The other CLI commands remain file-first unless they are explicitly named live acquisition, check, or assisted-authentication commands.

Safe live capture is Chromium-only, headless, non-interactive, and private. It requires every exact origin and writes page material only to a finite-retention private_raw cache entry:

go run ./cmd/browsertools capture chromium \
--url https://example.test/member \
--allow-origin https://example.test \
--cache-root ./.browsertools-cache \
--action-hint read_dashboard \
--retain-for 24h

The command blocks non-GET/HEAD requests, unapproved origins, child frames, service workers, WebSockets, popups, downloads, dialogs, file choosers, and non-essential resources. It uses finite navigation, total, request, response, ARIA-depth, evidence-size, and retention limits. Only cache metadata is printed; raw ARIA/JSON-LD content is never written to stdout. See Safe live capture for the review/redaction handoff.

Explicit private screenshots, traces, and minimal-content HAR can be captured as one short-lived, non-publishable ZIP:

go run ./cmd/browsertools rich-capture chromium \
--url https://example.test/member \
--allow-origin https://example.test \
--cache-root ./.browsertools-cache \
--artifact screenshot --artifact trace --artifact har \
--retain-for 1h

The command prints only cache metadata. Export requires a new 0600 file; review for secrets is mandatory, and cache delete requires the exact digest twice. Rich artifacts have no publication or normalized-evidence path.

After normalization, the terminal guide makes every capability and safety decision explicit and emits one deterministic envelope containing the accepted spec, generated profile, action-bound evidence, ambiguity decisions, and promotable review:

go run ./cmd/browsertools guide author \
--evidence ./evidence.json \
--at 2026-08-16T12:00:00Z \
--out ./guided-authoring.json

A separately selected live check can compare declared locators, waits, and output shapes with the current page without executing any profile macro or emitting page values:

go run ./cmd/browsertools live-check chromium \
--profile ./profile.yaml \
--url https://example.test/member \
--allow-origin https://example.test \
--action read_dashboard \
--at 2026-08-16T12:00:00Z \
--out ./live-check.json

Both paths keep sequence intent, side effects, confirmation, expiry, and ambiguity decisions human-authored. The live check reuses the exact-origin ephemeral capture policy, accepts plain CSS outputs but no Playwright selector language, and writes only profile-bound match/type facts. See Guided capability authoring and live checks.

The same profile-derived read-only checks can be compared without locator rewrites across explicitly installed engines:

go run ./cmd/browsertools portability check \
--profile ./profile.yaml \
--url https://example.test/member \
--allow-origin https://example.test \
--action read_dashboard \
--engine chromium --engine firefox --engine webkit \
--out ./portability.json

Chromium is the required baseline. Missing engines and shape differences are fixed value-free diagnostics, not silent fallbacks. See Private rich evidence and cross-engine portability.

Portable sign-in recipes use a separate additive contract and remain local to the workflow package:

go run ./cmd/browsertools auth-draft build \
--spec ./authentication-spec.yaml \
--out ./browser-authentication/member.yaml
go run ./cmd/browsertools auth-profile validate \
--input ./browser-authentication/member.yaml \
--at 2026-08-16T00:00:00Z
go run ./cmd/browsertools auth-review bundle \
--profile ./browser-authentication/member.yaml \
--at 2026-08-16T00:00:00Z \
--out ./browser-authentication/member.review.json

An explicit headed authoring command can then observe the exact recipe while the operator enters credentials and completes MFA directly in the browser:

go run ./cmd/browsertools auth-assist chromium \
--profile ./browser-authentication/member.yaml \
--flow member_login_push \
--approve-origin https://members.example.test \
--approve-origin https://login.example.test \
--post-budget member_login_push:3=2 \
--out ./browser-authentication/member.assisted.json

The profile supplies every locator, challenge alternative, submit step, and success condition; Browsertools does not infer them. Each selected flow runs in a separate visible ephemeral context. Browsertools navigates declared URLs and counts declared accessibility locators, but the operator performs every credential, click, and challenge step and signals completion with an empty terminal line. A POST is blocked unless its exact zero-based flow step has an explicit bounded --post-budget; all other mutating methods are blocked.

The 0600 output is created only after every context has closed and contains a selected uws.browser-authentication.1.0 profile, its digest-bound review, and value-free origin/count/request evidence. It cannot use stdin for a profile, stdout for the artifact, or overwrite a path. Authentication recipes are also excluded from static registry publication. Actual credentials, MFA responses, OAuth state, cookies, storage, and sessions stay in the browser or downstream private runtime. See Browser authentication profiles.

Account registration uses a separate explicitly mutating contract. Browsertools can validate, deterministically build, and digest-review only the inert recipe:

go run ./cmd/browsertools registration-draft build \
--spec ./registration-spec.yaml \
--out ./browser-registration/dedicated-test-user.yaml
go run ./cmd/browsertools registration-profile validate \
--input ./browser-registration/dedicated-test-user.yaml \
--at 2026-08-25T00:00:00Z
go run ./cmd/browsertools registration-review bundle \
--profile ./browser-registration/dedicated-test-user.yaml \
--at 2026-08-25T00:00:00Z \
--out ./browser-registration/dedicated-test-user.review.json

These commands are file-only and never launch a browser, contact a target, resolve a symbolic credential, submit a registration, handle CAPTCHA/MFA/email verification, approve a run, or perform cleanup. Registration profiles and reviews remain package-local and are excluded from the browser capability registry. See Browser registration profiles.

The typed registrationauthor.Build path combines one current reduced registration observation with a complete registrationdraft.Spec, exact reviewed candidate IDs, selected submit candidate and flow, approved origins, and explicit fixed call controls. It reconstructs the current-generation candidate IDs, binds the one accessibility-name submit, and emits the exact M26 review message without inferring any profile or cleanup field. After clean session teardown, registrationauthorresult.FinalizePrivate independently reconstructs and strict-decodes the M26 result before and after an anchored owner-only, create-once write; its path remains process-private.

The standalone producer uses that complete path:

browsertools registration-author-session chromium \
--private-root ./private-registration-results \
--driver-dir "$PLAYWRIGHT_DRIVER_PATH"

Stdin and stdout are reserved for registration author-session NDJSON. The worker defaults to v1; --protocol v2 deliberately selects the additive retained-query contract and guarded Chromium routing. The private root must already be a mode-0700 directory. The command never prints the resulting file name or digest, and it provides no registration runtime or submit command.

Caller-supplied raw captures and derived artifacts can be kept in an explicit private local cache. Raw entries can never be publication eligible:

go run ./cmd/browsertools cache put \
--root ./.browsertools-cache --input ./capture.json \
--kind private_raw --media-type application/json \
--created-at 2026-08-14T00:00:00Z
go run ./cmd/browsertools cache list \
--root ./.browsertools-cache --at 2026-08-14T12:00:00Z
go run ./cmd/browsertools cache prune \
--root ./.browsertools-cache --at 2026-09-14T00:00:00Z
go run ./cmd/browsertools cache delete \
--root ./.browsertools-cache --id sha256:EXACT_ID --confirm-id sha256:EXACT_ID

What It Owns

  • A complete typed model and validation helpers for UWS browser-profile documents.
  • Typed validation, deterministic drafting, digest-bound review, freshness, and local discovery for package-local uws.browser-authentication.1.0 recipes.
  • Typed offline validation, deterministic explicit drafting, digest-bound review, and freshness for package-local uws.browser-registration.1.0 recipes.
  • Secret-free evidence records from browser and scraper tooling.
  • Draft profile generation from reviewed evidence.
  • Review bundles with validation, confidence, expiry, side-effect, and revalidation notes.
  • Deterministic fixture-only revalidation and digest-bound promotion gates.
  • A bounded, content-addressed private cache for caller-supplied experiences, normalized evidence, profiles, and review bundles.
  • Canonical, digest-bound, lifecycle-assessed publication bundles for reviewed profiles, safe evidence, and optional inert UWS companions.
  • A service-free static registry layout, atomic local publisher, bounded local/HTTPS reader, and local browser-source discovery report.
  • Browser-profile, scraper/crawler, and browser-backed wrapper examples.
  • Optional adapters for Playwright, llm-scraper, Crawl4AI, and Firecrawl outputs.
  • An isolated Playwright-Go acquisition boundary, pinned capability policy, and offline installation doctor for authoring-only browser tooling.
  • Explicit headless Chromium acquisition into the private raw cache with exact origins, ephemeral context destruction, and closed activity/resource bounds.
  • Deterministic terminal-guided authoring that binds explicit intent, reviewed evidence, decisions, a valid profile, and a promotable review.
  • Value-free Chromium live checks for declared locators, waits, and output shapes without macro execution.
  • Explicit short-lived screenshot/trace/HAR bundles with mandatory secret review, no publication path, and exact-ID deletion.
  • Fresh Chromium-baseline Firefox/WebKit comparisons of the same value-free profile probes, plus documented browser.1.6 contract pressure.
  • Headed manual authentication observation with separate ephemeral contexts, exact preapproved origins, step-scoped POST ceilings, and local value-free draft/review bundles.

What It Does Not Own

  • UWS schema and workflow semantics. Those live in github.com/OpenUdon/uws.
  • OpenAPI/API-source discovery and provider catalog metadata. Those belong in github.com/OpenUdon/apitools.
  • Production browser execution, runtime credential resolution, retained cookies/sessions, retries, account selection, or production side effects.
  • A general Playwright, WebDriver, Puppeteer, or scraping DSL.
  • Implicit browser launch or uploading cached content. Acquisition commands are separately selected; cache commands are local and offline, and publication has a separate verification boundary.
  • Accounts, membership, a registry database, remote writes, or deployment credentials. Static catalogs are reviewed and deployed by existing repository/hosting workflows.
  • Publication of authentication recipes through the static browser capability registry.
  • Publication of registration recipes through the static browser capability registry, or live registration/account cleanup of any kind.

Why Not Just OpenAPI?

OpenAPI should describe a stable HTTP service. If you build a browser-backed wrapper service, OpenAPI should describe that wrapper. Browsertools can also emit an advisory overlay sidecar for the wrapper, linking OpenAPI operations to reviewed browser-profile actions and review bundles.

browser-profile describes the UI binding behind the wrapper or behind a UWS browser operation:

website UI
-> browsertools-reviewed profile
-> browser runtime executes profile

or:

website UI
-> browser-backed wrapper service
-> OpenAPI describes wrapper
-> UWS binds to wrapper API

Documentation

Development

go test ./...
go vet ./...
GOWORK=off go run golang.org/x/vuln/cmd/govulncheck@v1.6.0 ./...
git diff --check
(cd ../uws && go test ./...)

Default tests use fakes and synthetic fixtures; they do not install or launch browsers and do not contact the network.

An installed-browser loopback integration test is opt-in:

BROWSERTOOLS_LIVE_TEST=1 go test ./capture -run PlaywrightLiveCaptureLoopback

Headed authentication behavior is covered by browser-free policy/state-machine tests by default. A real site is never contacted by the test suite. An installed-browser headed smoke test is separately opt-in and loopback-only:

BROWSERTOOLS_AUTH_LIVE_TEST=1 go test ./capture -run PlaywrightAuthHeadedLoopback

Rich evidence and cross-engine smoke tests are independently gated and remain loopback-only:

BROWSERTOOLS_RICH_LIVE_TEST=1 go test ./capture -run PlaywrightRichCaptureLoopback
BROWSERTOOLS_PORTABILITY_LIVE_TEST=1 go test ./capture -run PlaywrightPortabilityLoopback

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); GitHub - OpenUdon/browsertools · GitHub
Skip to content

Latest commit

History

72 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

browsertools

browsertools is OpenUdon's tooling project for turning real website UI evidence into reviewed UWS browser capability profiles.

It exists for the gap where a task is exposed through a web UI and no suitable API source document is available. The output is not a browser command trace and not an OpenAPI substitute. The output is a portable, reviewed browser-profile document that a UWS workflow can bind to.

real website UI
-> browsertools using Playwright / llm-scraper / Crawl4AI / Firecrawl
-> reviewed browser-profile
-> UWS operation binds to browser-profile action

Where Browsertools Fits

OpenUdon's iCoT is the primary end-user authoring entry point across API, browser, and runtime-handoff sources. iCoT retains goal interviewing, LLM/human interaction, source selection, and package staging. For UI-only acquisition, the distributed icot executable re-executes a private copy of itself as a separate process using Browsertools' importable worker; an external browsertools CLI remains available for experts and maintainers.

Browsertools owns Playwright-based acquisition, browser safety policy, profile synthesis, and the shared validation library for browser capability and authentication profiles, plus offline validation/draft/review tooling for the separate UWS browser-registration profile. Its CLI is primarily a machine- facing protocol plus maintainer and offline tooling, not a parallel end-user authoring product. Browsertools is not the production runtime; runtime replay belongs to Udon and Browserdriver. See the canonical OpenUdon integration reference for the two integration paths and full ownership split.

For UWS 1.9.1 advisory integrity analysis, package github.com/OpenUdon/browsertools/contenttrust builds a resolver from reviewed profiles keyed by sourceDescription name. Browser-derived outputs default to untrusted while retaining their declared value shape. Navigation and option selection parameters are authority-bearing, confirmation prompts are instructions, and typed text remains data. The resolver performs no browser work and never changes validation or execution.

Authenticated live authoring uses the strict browsertools.author-session.v2 NDJSON boundary. Human-reviewed MFA kinds and up to 16 final accessibility outputs produce one private browsertools.authenticated-authoring.v2 envelope; the protocol carries no credential, page value, cookie, or browser state. See Authenticated goal-directed browser authoring.

Registration authoring has separate browser-independent contracts. V1 (browsertools.registration-author-session.v1 and private browsertools.registration-authoring.v1) remains query-free. Additive v2 (browsertools.registration-author-session.v2 and private browsertools.registration-authoring.v2) admits only bounded canonical literal structural queries and validates them on all session and retained BRP navigations. Both continue only approved-origin GET/HEAD traffic and bind one reviewed inert BRP without claiming a submit, account attempt, session, or supported runtime. Canonical unapproved non-navigation GET/HEAD subresources are counted and aborted before contact without expanding the allowlist or poisoning an otherwise clean observation; unsafe navigation, methods, and persistent channels remain fatal. A guarded typed Chromium backend and deterministic explicit candidate builder implement those contracts. The importable registrationauthorworker and browsertools registration-author-session chromium expose that backend through the same closed no-submit wire and finalize the result only under an explicit owner-only private root. See Browser registration profiles.

Page-controlled frame names cross the same canonical reduction boundary as candidate labels. Exact backend-reported MFA subsets are preserved, and the finite total timeout charges browser work rather than human credential/MFA wait time.

The authorworker package is the supported process-entry adapter for browsertools author-session chromium and the hidden iCoT worker. It accepts context, private root, optional driver directory, interruptible owned stdin, and stdout. SIGINT/SIGTERM or parent cancellation closes protocol input, then waits for browser teardown; failed close negotiation or teardown exits nonzero. Embedding it does not move Playwright into the iCoT engine or HTTP server process.

The separate registrationauthorworker is the supported process entry for no-submit BRP production. It performs read-only pinned-driver preflight, owns the closeable NDJSON input and headed browser lifetime, and creates an independently reconstructed result only after clean teardown. Its API and CLI return no result path or digest. A re-executing parent owns executable hashing, minimal child environment, and process-group termination. On Linux, an administrator-provisioned CHROME_DEVEL_SANDBOX is forwarded to Chromium only after exact mode, root ownership, link count, setuid-filesystem, resolved-path, and complete ancestor-control checks; sandbox disabling is never supported.

Accessibility-label reduction is a useful heuristic, not data loss prevention. Ordinary names, identifiers, and order numbers can remain in reduced observations and reviewed traces. Operators must review those records before retaining or sharing them.

Quick Start

go get github.com/OpenUdon/browsertools

The full pipeline from evidence to a reviewable bundle:

import (
"time""github.com/OpenUdon/browsertools/adapter""github.com/OpenUdon/browsertools/adapter/playwright""github.com/OpenUdon/browsertools/bundle""github.com/OpenUdon/browsertools/draft""github.com/OpenUdon/browsertools/evidence""github.com/OpenUdon/browsertools/profile""github.com/OpenUdon/browsertools/review"
)
// 1. Import saved Playwright snapshot as normalized evidence.a:=&playwright.Adapter{}
records, err:=a.Import(snapshotJSON, adapter.Options{
Origin: "https://example.test",
ActionHint: "read_status",
RedactionStatus: evidence.RedactionNotRequired,
})
// 2. Add explicit action intent. Evidence never invents a click or assumes// that an action is read-only.result, err:=draft.Build(records, draft.Spec{
Info: profile.Info{Title: "Example", Origin: profile.Origins{"https://example.test"}},
ObservationKind: profile.ObservationAccessibilitySnapshot,
Confidence: profile.ConfidenceMedium,
ExpiresAfter: "P30D",
Actions: map[string]draft.ActionSpec{
"read_status": {
Sequence: []profile.Step{
{Kind: profile.StepNavigate, Navigate: "/status"},
{Kind: profile.StepWaitFor, WaitFor: &profile.WaitForCondition{
Locator: &profile.Locator{Role: profile.RoleStatus, Name: "OK"},
}},
},
SideEffects: []profile.SideEffect{profile.SideEffectReadOnly},
ConfirmationPolicy: profile.ConfirmationPolicy{Required: false},
},
},
})
// 3. Build a digest-bound bundle at an explicit assessment time.assessedAt:=time.Now().UTC()
reviewed, err:=review.Build(result.Profile, records, result.Decisions, assessedAt)
iferr!=nil||!reviewed.Promotable() {
// fix gaps before promoting
}
// 4. Wrap the exact reviewed inputs in an inert publication bundle.published, err:=bundle.Build(bundle.BuildOptions{
ID: "example/status", Release: "1.0.0", Source: "reviewed_fixture",
License: "CC0-1.0", Profile: result.Profile, Review: reviewed,
Evidence: records, PublishedAt: assessedAt,
})

The CLI exposes the same offline pipeline:

go run ./cmd/browsertools profile validate --input ./profiles/example.yaml
go run ./cmd/browsertools evidence import \
--adapter playwright --input ./capture.json \
--origin https://example.test --redaction-status not_required \
--out ./evidence.json
go run ./cmd/browsertools draft build \
--evidence ./evidence.json --spec ./draft-spec.yaml \
--out ./profile.yaml
go run ./cmd/browsertools review bundle \
--profile ./profile.yaml --evidence ./evidence.json \
--at 2026-08-14T00:00:00Z --out ./review-bundle.json
go run ./cmd/browsertools revalidate check \
--profile ./profile.yaml --evidence ./evidence.json \
--at 2026-08-14T00:00:00Z --out ./revalidation.json
go run ./cmd/browsertools bundle build \
--id example/status --release 1.0.0 \
--profile ./profile.yaml --review ./review-bundle.json \
--evidence ./evidence.json --source reviewed_fixture --license CC0-1.0 \
--published-at 2026-08-14T00:00:00Z --out ./capability-bundle.json
go run ./cmd/browsertools bundle verify \
--input ./capability-bundle.json --at 2026-08-14T00:00:00Z
go run ./cmd/browsertools registry publish \
--root ./public-registry --bundle ./capability-bundle.json \
--at 2026-08-14T00:00:00Z
go run ./cmd/browsertools registry search \
--location ./public-registry --query status \
--at 2026-08-14T00:00:00Z

Browser acquisition is an explicit, separately installed authoring feature. Browsertools pins Playwright-Go v0.6201.0 (Playwright 1.62.1). Install the matching driver and Chromium deliberately, then verify the local installation:

go run github.com/mxschmitt/playwright-go/cmd/playwright@v0.6201.0 install chromium
go run ./cmd/browsertools playwright doctor --engine chromium

Before playwright doctor or an author session starts, Browsertools verifies the installed Node executable, CLI, and exact Playwright 1.62.1 package using read-only filesystem checks. It creates no cache directory, invokes no installer, and contacts no network. The doctor then starts and stops only that installed driver; its full local CLI report may include the browser executable path, while the separate UI-safe report omits executable and private paths. It does not contact a site or launch a browser. The other CLI commands remain file-first unless they are explicitly named live acquisition, check, or assisted-authentication commands.

Safe live capture is Chromium-only, headless, non-interactive, and private. It requires every exact origin and writes page material only to a finite-retention private_raw cache entry:

go run ./cmd/browsertools capture chromium \
--url https://example.test/member \
--allow-origin https://example.test \
--cache-root ./.browsertools-cache \
--action-hint read_dashboard \
--retain-for 24h

The command blocks non-GET/HEAD requests, unapproved origins, child frames, service workers, WebSockets, popups, downloads, dialogs, file choosers, and non-essential resources. It uses finite navigation, total, request, response, ARIA-depth, evidence-size, and retention limits. Only cache metadata is printed; raw ARIA/JSON-LD content is never written to stdout. See Safe live capture for the review/redaction handoff.

Explicit private screenshots, traces, and minimal-content HAR can be captured as one short-lived, non-publishable ZIP:

go run ./cmd/browsertools rich-capture chromium \
--url https://example.test/member \
--allow-origin https://example.test \
--cache-root ./.browsertools-cache \
--artifact screenshot --artifact trace --artifact har \
--retain-for 1h

The command prints only cache metadata. Export requires a new 0600 file; review for secrets is mandatory, and cache delete requires the exact digest twice. Rich artifacts have no publication or normalized-evidence path.

After normalization, the terminal guide makes every capability and safety decision explicit and emits one deterministic envelope containing the accepted spec, generated profile, action-bound evidence, ambiguity decisions, and promotable review:

go run ./cmd/browsertools guide author \
--evidence ./evidence.json \
--at 2026-08-16T12:00:00Z \
--out ./guided-authoring.json

A separately selected live check can compare declared locators, waits, and output shapes with the current page without executing any profile macro or emitting page values:

go run ./cmd/browsertools live-check chromium \
--profile ./profile.yaml \
--url https://example.test/member \
--allow-origin https://example.test \
--action read_dashboard \
--at 2026-08-16T12:00:00Z \
--out ./live-check.json

Both paths keep sequence intent, side effects, confirmation, expiry, and ambiguity decisions human-authored. The live check reuses the exact-origin ephemeral capture policy, accepts plain CSS outputs but no Playwright selector language, and writes only profile-bound match/type facts. See Guided capability authoring and live checks.

The same profile-derived read-only checks can be compared without locator rewrites across explicitly installed engines:

go run ./cmd/browsertools portability check \
--profile ./profile.yaml \
--url https://example.test/member \
--allow-origin https://example.test \
--action read_dashboard \
--engine chromium --engine firefox --engine webkit \
--out ./portability.json

Chromium is the required baseline. Missing engines and shape differences are fixed value-free diagnostics, not silent fallbacks. See Private rich evidence and cross-engine portability.

Portable sign-in recipes use a separate additive contract and remain local to the workflow package:

go run ./cmd/browsertools auth-draft build \
--spec ./authentication-spec.yaml \
--out ./browser-authentication/member.yaml
go run ./cmd/browsertools auth-profile validate \
--input ./browser-authentication/member.yaml \
--at 2026-08-16T00:00:00Z
go run ./cmd/browsertools auth-review bundle \
--profile ./browser-authentication/member.yaml \
--at 2026-08-16T00:00:00Z \
--out ./browser-authentication/member.review.json

An explicit headed authoring command can then observe the exact recipe while the operator enters credentials and completes MFA directly in the browser:

go run ./cmd/browsertools auth-assist chromium \
--profile ./browser-authentication/member.yaml \
--flow member_login_push \
--approve-origin https://members.example.test \
--approve-origin https://login.example.test \
--post-budget member_login_push:3=2 \
--out ./browser-authentication/member.assisted.json

The profile supplies every locator, challenge alternative, submit step, and success condition; Browsertools does not infer them. Each selected flow runs in a separate visible ephemeral context. Browsertools navigates declared URLs and counts declared accessibility locators, but the operator performs every credential, click, and challenge step and signals completion with an empty terminal line. A POST is blocked unless its exact zero-based flow step has an explicit bounded --post-budget; all other mutating methods are blocked.

The 0600 output is created only after every context has closed and contains a selected uws.browser-authentication.1.0 profile, its digest-bound review, and value-free origin/count/request evidence. It cannot use stdin for a profile, stdout for the artifact, or overwrite a path. Authentication recipes are also excluded from static registry publication. Actual credentials, MFA responses, OAuth state, cookies, storage, and sessions stay in the browser or downstream private runtime. See Browser authentication profiles.

Account registration uses a separate explicitly mutating contract. Browsertools can validate, deterministically build, and digest-review only the inert recipe:

go run ./cmd/browsertools registration-draft build \
--spec ./registration-spec.yaml \
--out ./browser-registration/dedicated-test-user.yaml
go run ./cmd/browsertools registration-profile validate \
--input ./browser-registration/dedicated-test-user.yaml \
--at 2026-08-25T00:00:00Z
go run ./cmd/browsertools registration-review bundle \
--profile ./browser-registration/dedicated-test-user.yaml \
--at 2026-08-25T00:00:00Z \
--out ./browser-registration/dedicated-test-user.review.json

These commands are file-only and never launch a browser, contact a target, resolve a symbolic credential, submit a registration, handle CAPTCHA/MFA/email verification, approve a run, or perform cleanup. Registration profiles and reviews remain package-local and are excluded from the browser capability registry. See Browser registration profiles.

The typed registrationauthor.Build path combines one current reduced registration observation with a complete registrationdraft.Spec, exact reviewed candidate IDs, selected submit candidate and flow, approved origins, and explicit fixed call controls. It reconstructs the current-generation candidate IDs, binds the one accessibility-name submit, and emits the exact M26 review message without inferring any profile or cleanup field. After clean session teardown, registrationauthorresult.FinalizePrivate independently reconstructs and strict-decodes the M26 result before and after an anchored owner-only, create-once write; its path remains process-private.

The standalone producer uses that complete path:

browsertools registration-author-session chromium \
--private-root ./private-registration-results \
--driver-dir "$PLAYWRIGHT_DRIVER_PATH"

Stdin and stdout are reserved for registration author-session NDJSON. The worker defaults to v1; --protocol v2 deliberately selects the additive retained-query contract and guarded Chromium routing. The private root must already be a mode-0700 directory. The command never prints the resulting file name or digest, and it provides no registration runtime or submit command.

Caller-supplied raw captures and derived artifacts can be kept in an explicit private local cache. Raw entries can never be publication eligible:

go run ./cmd/browsertools cache put \
--root ./.browsertools-cache --input ./capture.json \
--kind private_raw --media-type application/json \
--created-at 2026-08-14T00:00:00Z
go run ./cmd/browsertools cache list \
--root ./.browsertools-cache --at 2026-08-14T12:00:00Z
go run ./cmd/browsertools cache prune \
--root ./.browsertools-cache --at 2026-09-14T00:00:00Z
go run ./cmd/browsertools cache delete \
--root ./.browsertools-cache --id sha256:EXACT_ID --confirm-id sha256:EXACT_ID

What It Owns

  • A complete typed model and validation helpers for UWS browser-profile documents.
  • Typed validation, deterministic drafting, digest-bound review, freshness, and local discovery for package-local uws.browser-authentication.1.0 recipes.
  • Typed offline validation, deterministic explicit drafting, digest-bound review, and freshness for package-local uws.browser-registration.1.0 recipes.
  • Secret-free evidence records from browser and scraper tooling.
  • Draft profile generation from reviewed evidence.
  • Review bundles with validation, confidence, expiry, side-effect, and revalidation notes.
  • Deterministic fixture-only revalidation and digest-bound promotion gates.
  • A bounded, content-addressed private cache for caller-supplied experiences, normalized evidence, profiles, and review bundles.
  • Canonical, digest-bound, lifecycle-assessed publication bundles for reviewed profiles, safe evidence, and optional inert UWS companions.
  • A service-free static registry layout, atomic local publisher, bounded local/HTTPS reader, and local browser-source discovery report.
  • Browser-profile, scraper/crawler, and browser-backed wrapper examples.
  • Optional adapters for Playwright, llm-scraper, Crawl4AI, and Firecrawl outputs.
  • An isolated Playwright-Go acquisition boundary, pinned capability policy, and offline installation doctor for authoring-only browser tooling.
  • Explicit headless Chromium acquisition into the private raw cache with exact origins, ephemeral context destruction, and closed activity/resource bounds.
  • Deterministic terminal-guided authoring that binds explicit intent, reviewed evidence, decisions, a valid profile, and a promotable review.
  • Value-free Chromium live checks for declared locators, waits, and output shapes without macro execution.
  • Explicit short-lived screenshot/trace/HAR bundles with mandatory secret review, no publication path, and exact-ID deletion.
  • Fresh Chromium-baseline Firefox/WebKit comparisons of the same value-free profile probes, plus documented browser.1.6 contract pressure.
  • Headed manual authentication observation with separate ephemeral contexts, exact preapproved origins, step-scoped POST ceilings, and local value-free draft/review bundles.

What It Does Not Own

  • UWS schema and workflow semantics. Those live in github.com/OpenUdon/uws.
  • OpenAPI/API-source discovery and provider catalog metadata. Those belong in github.com/OpenUdon/apitools.
  • Production browser execution, runtime credential resolution, retained cookies/sessions, retries, account selection, or production side effects.
  • A general Playwright, WebDriver, Puppeteer, or scraping DSL.
  • Implicit browser launch or uploading cached content. Acquisition commands are separately selected; cache commands are local and offline, and publication has a separate verification boundary.
  • Accounts, membership, a registry database, remote writes, or deployment credentials. Static catalogs are reviewed and deployed by existing repository/hosting workflows.
  • Publication of authentication recipes through the static browser capability registry.
  • Publication of registration recipes through the static browser capability registry, or live registration/account cleanup of any kind.

Why Not Just OpenAPI?

OpenAPI should describe a stable HTTP service. If you build a browser-backed wrapper service, OpenAPI should describe that wrapper. Browsertools can also emit an advisory overlay sidecar for the wrapper, linking OpenAPI operations to reviewed browser-profile actions and review bundles.

browser-profile describes the UI binding behind the wrapper or behind a UWS browser operation:

website UI
-> browsertools-reviewed profile
-> browser runtime executes profile

or:

website UI
-> browser-backed wrapper service
-> OpenAPI describes wrapper
-> UWS binds to wrapper API

Documentation

Development

go test ./...
go vet ./...
GOWORK=off go run golang.org/x/vuln/cmd/govulncheck@v1.6.0 ./...
git diff --check
(cd ../uws && go test ./...)

Default tests use fakes and synthetic fixtures; they do not install or launch browsers and do not contact the network.

An installed-browser loopback integration test is opt-in:

BROWSERTOOLS_LIVE_TEST=1 go test ./capture -run PlaywrightLiveCaptureLoopback

Headed authentication behavior is covered by browser-free policy/state-machine tests by default. A real site is never contacted by the test suite. An installed-browser headed smoke test is separately opt-in and loopback-only:

BROWSERTOOLS_AUTH_LIVE_TEST=1 go test ./capture -run PlaywrightAuthHeadedLoopback

Rich evidence and cross-engine smoke tests are independently gated and remain loopback-only:

BROWSERTOOLS_RICH_LIVE_TEST=1 go test ./capture -run PlaywrightRichCaptureLoopback
BROWSERTOOLS_PORTABILITY_LIVE_TEST=1 go test ./capture -run PlaywrightPortabilityLoopback

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages