{"_id":"@blopai/browser-harness","_rev":"11-b325b5efe54b7fa9796347bf658e800a","name":"@blopai/browser-harness","dist-tags":{"latest":"0.1.10"},"versions":{"0.1.0":{"name":"@blopai/browser-harness","version":"0.1.0","keywords":["browser","playwright","agent","harness","e2e","tools","cdp","testing"],"license":"MIT","_id":"@blopai/browser-harness@0.1.0","maintainers":[{"name":"hananinas","email":"hanani.nas@gmail.com"}],"homepage":"https://github.com/blop-oss/browser-harness#readme","bugs":{"url":"https://github.com/blop-oss/browser-harness/issues"},"bin":{"blop-browser":"dist/cli.js"},"dist":{"shasum":"cb713609065309019e41fbf68c23f05bdcd76233","tarball":"https://registry.npmjs.org/@blopai/browser-harness/-/browser-harness-0.1.0.tgz","fileCount":82,"integrity":"sha512-MMGsK2ueTYJUZmtbOdcSeP6nAM0fq54PE7dmfpFhKf69at+3SZ1dEKMByZCh7vgOOYWSLQzna8cgBcZbPBHk/Q==","signatures":[{"sig":"MEUCIEr8F/lvgk3WSZXhzZ6sm4L95ab00X24lKuHjl8CDa6dAiEAo+2H6jfp2yPLHYzjVH2qsVE2L5ClXUMO9xfH9CXgGno=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":424540},"type":"module","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"93553a6e2f1af243d0c3abec0a0bdac68b9776cf","scripts":{"test":"bun run build && bun test test/browser test/session test/benchmarks test/cli","build":"tsc","clean":"rm -rf dist","test:cli":"bun test test/cli","typecheck":"tsc --noEmit","test:browser":"bun test test/browser","test:session":"bun test test/session","prepublishOnly":"npm run clean && npm run build","test:benchmarks":"bun test test/benchmarks"},"_npmUser":{"name":"hananinas","email":"hanani.nas@gmail.com"},"repository":{"url":"git+https://github.com/blop-oss/browser-harness.git","type":"git"},"_npmVersion":"10.9.4","description":"Playwright browser harness for AI agents: controlled native tools, sessions, screencast, and optional Docker browser sandbox.","directories":{},"_nodeVersion":"22.22.1","dependencies":{"playwright":"^1.59.1","camoufox-js":"0.7.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.8.3","@types/node":"^22.15.18"},"_npmOperationalInternal":{"tmp":"tmp/browser-harness_0.1.0_1784823589262_0.9041314406729606","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@blopai/browser-harness","version":"0.1.1","keywords":["browser","playwright","agent","harness","e2e","tools","cdp","testing"],"license":"MIT","_id":"@blopai/browser-harness@0.1.1","maintainers":[{"name":"hananinas","email":"hanani.nas@gmail.com"}],"homepage":"https://github.com/blop-oss/browser-harness#readme","bugs":{"url":"https://github.com/blop-oss/browser-harness/issues"},"bin":{"blop-browser":"dist/cli.js"},"dist":{"shasum":"d1d5762839f11c82681e3824139eb043cfdfa4a1","tarball":"https://registry.npmjs.org/@blopai/browser-harness/-/browser-harness-0.1.1.tgz","fileCount":82,"integrity":"sha512-3c9GYsAeIDoKznoyZjksx8JqeQ1FJ8ZIpSw9r2rg6z8Vkb8eTlZyKnxM2hfnY3corrCbUGn8gnW8Tjzyf7Tzmw==","signatures":[{"sig":"MEUCIApBaxbGnNlc0ULVOgiZe4gAJJrzOJlvhOVtkcXhmuk+AiEAudpFuHKIbULj5C1dyT5YPgq+vBlwGc8bdO5iGfsH0VQ=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@blopai%2fbrowser-harness@0.1.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":424540},"type":"module","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"f21682494605e6e47378af9f9fb1fb2fc1b3daf3","scripts":{"test":"bun run build && bun test test/browser test/session test/benchmarks test/cli","build":"tsc","clean":"rm -rf dist","test:cli":"bun test test/cli","typecheck":"tsc --noEmit","test:browser":"bun test test/browser","test:session":"bun test test/session","prepublishOnly":"npm run clean && npm run build","test:benchmarks":"bun test test/benchmarks"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:189fe6e5-4815-49f6-9e84-e005c07cc06f"}},"repository":{"url":"git+https://github.com/blop-oss/browser-harness.git","type":"git"},"_npmVersion":"11.5.1","description":"Playwright browser harness for AI agents: controlled native tools, sessions, screencast, and optional Docker browser sandbox.","directories":{},"_nodeVersion":"22.14.0","dependencies":{"playwright":"^1.59.1","camoufox-js":"0.7.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.8.3","@types/node":"^22.15.18"},"_npmOperationalInternal":{"tmp":"tmp/browser-harness_0.1.1_1784824204367_0.17687616485040736","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@blopai/browser-harness","version":"0.1.2","keywords":["browser","playwright","agent","harness","e2e","tools","cdp","testing"],"license":"MIT","_id":"@blopai/browser-harness@0.1.2","maintainers":[{"name":"hananinas","email":"hanani.nas@gmail.com"}],"homepage":"https://github.com/blop-oss/browser-harness#readme","bugs":{"url":"https://github.com/blop-oss/browser-harness/issues"},"bin":{"blop-browser":"dist/cli.js"},"dist":{"shasum":"0d0788c29c79da01ef143f29968b67775ffb3c22","tarball":"https://registry.npmjs.org/@blopai/browser-harness/-/browser-harness-0.1.2.tgz","fileCount":82,"integrity":"sha512-ioSWUYndPdDFeVWkjMbV78dF7p/8ldPhZ00XjfqsrrA3/0HNJEdIy/AJrivKgACo6kNvZG2F/K+aH8oW+KLx4g==","signatures":[{"sig":"MEUCIFRmg/YCNiovCmtKLVN2ZGgRd5bufofuiKXvtOV3pVtOAiEA3YzrX0BXjS+5iNcqYMsdRBf8XK2DWCrjRYzCmk49Ao4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@blopai%2fbrowser-harness@0.1.2","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":424363},"type":"module","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"5806f33260715b30403c5393783273a00ff0477d","scripts":{"test":"bun run build && bun test test/browser test/session test/benchmarks test/cli","build":"tsc","clean":"rm -rf dist","test:cli":"bun test test/cli","typecheck":"tsc --noEmit","test:browser":"bun test test/browser","test:session":"bun test test/session","prepublishOnly":"npm run clean && npm run build","test:benchmarks":"bun test test/benchmarks"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:189fe6e5-4815-49f6-9e84-e005c07cc06f"}},"repository":{"url":"git+https://github.com/blop-oss/browser-harness.git","type":"git"},"_npmVersion":"11.5.1","description":"Playwright browser harness for AI agents: controlled native tools, sessions, screencast, and optional Docker browser sandbox.","directories":{},"_nodeVersion":"22.14.0","dependencies":{"playwright":"^1.59.1","camoufox-js":"0.7.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.8.3","@types/node":"^22.15.18"},"_npmOperationalInternal":{"tmp":"tmp/browser-harness_0.1.2_1784825934948_0.35834572882477334","host":"s3://npm-registry-packages-npm-production"}},"0.1.3":{"name":"@blopai/browser-harness","version":"0.1.3","keywords":["browser","playwright","agent","harness","e2e","tools","cdp","testing"],"license":"MIT","_id":"@blopai/browser-harness@0.1.3","maintainers":[{"name":"hananinas","email":"hanani.nas@gmail.com"}],"homepage":"https://github.com/blop-oss/browser-harness#readme","bugs":{"url":"https://github.com/blop-oss/browser-harness/issues"},"bin":{"blop-browser":"dist/cli.js"},"dist":{"shasum":"d8dbb09f6a55555b432a350370ce1cfd6223adad","tarball":"https://registry.npmjs.org/@blopai/browser-harness/-/browser-harness-0.1.3.tgz","fileCount":82,"integrity":"sha512-igco76hGUdI7UjDEi9OgkhsCtIIHbDVD+OG6Suvvq+eTOa2/cS7cUuLz5cJ3zQOMH4KZ3ZKgoyM7mpzlh9Qs8g==","signatures":[{"sig":"MEYCIQCTpyQh/UUPwcxKYNeGfc97MZxNwidl2z+CXdBXCS+9xAIhAPTWNWLsQmDcbk1OSTUmcyMvNDUFEIey6oOOjQnQ1Xyd","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@blopai%2fbrowser-harness@0.1.3","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":442660},"type":"module","engines":{"node":">=20"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"58f36feb9f668e974c519f4f50072ceed8fb9d2e","scripts":{"test":"bun run build && bun test test/browser test/session test/benchmarks test/cli","build":"tsc","clean":"rm -rf dist","test:cli":"bun test test/cli","typecheck":"tsc --noEmit","test:browser":"bun test test/browser","test:session":"bun test test/session","prepublishOnly":"npm run clean && npm run build","test:benchmarks":"bun test test/benchmarks"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:189fe6e5-4815-49f6-9e84-e005c07cc06f"}},"repository":{"url":"git+https://github.com/blop-oss/browser-harness.git","type":"git"},"_npmVersion":"11.5.1","description":"Playwright browser harness for AI agents: controlled native tools, sessions, screencast, and optional Docker browser sandbox.","directories":{},"_nodeVersion":"22.14.0","dependencies":{"playwright":"^1.59.1","camoufox-js":"0.7.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.8.3","@types/node":"^22.15.18"},"_npmOperationalInternal":{"tmp":"tmp/browser-harness_0.1.3_1784834418669_0.6160215003282601","host":"s3://npm-registry-packages-npm-production"}},"0.1.4":{"name":"@blopai/browser-harness","version":"0.1.4","keywords":["browser","playwright","agent","harness","e2e","tools","cdp","testing"],"license":"MIT","_id":"@blopai/browser-harness@0.1.4","maintainers":[{"name":"hananinas","email":"hanani.nas@gmail.com"}],"homepage":"https://github.com/blop-oss/browser-harness#readme","bugs":{"url":"https://github.com/blop-oss/browser-harness/issues"},"bin":{"blop-browser":"dist/cli.js"},"dist":{"shasum":"f6baa4b928a6426edf58778f62512e1414220acb","tarball":"https://registry.npmjs.org/@blopai/browser-harness/-/browser-harness-0.1.4.tgz","fileCount":87,"integrity":"sha512-wv84jAa9h3YkhNvcq6mMNAMTXzf8hymKG4Fn6ept2Zz3T06f7RTSBbe3Tp9G3yN78QW1aewLj4CChVvtnJVLLQ==","signatures":[{"sig":"MEQCIDSByLC12C51LycAVneg4fcvK87SZ2ssMXvBDNhVT2/vAiB2aXRyXWZcG7DC6RNZP0os8qEiJYkWW33JjJIqWJOryQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@blopai%2fbrowser-harness@0.1.4","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":465067},"type":"module","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"5164fd9eac38d3862c4f3d56a326a4f1201d2ab2","scripts":{"test":"bun run build && bun test test/browser test/session test/benchmarks test/cli","build":"tsc","clean":"rm -rf dist","test:cli":"bun test test/cli","typecheck":"tsc --noEmit","test:browser":"bun test test/browser","test:session":"bun test test/session","prepublishOnly":"npm run clean && npm run build","test:benchmarks":"bun test test/benchmarks"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:189fe6e5-4815-49f6-9e84-e005c07cc06f"}},"repository":{"url":"git+https://github.com/blop-oss/browser-harness.git","type":"git"},"_npmVersion":"11.5.1","description":"Playwright browser harness for AI agents: controlled native tools, sessions, screencast, and optional Docker browser sandbox.","directories":{},"_nodeVersion":"22.14.0","dependencies":{"playwright":"^1.59.1","camoufox-js":"0.11.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.8.3","@types/node":"^22.15.18"},"_npmOperationalInternal":{"tmp":"tmp/browser-harness_0.1.4_1784905909381_0.22835241068768886","host":"s3://npm-registry-packages-npm-production"}},"0.1.5":{"name":"@blopai/browser-harness","version":"0.1.5","keywords":["browser","playwright","agent","harness","e2e","tools","cdp","testing"],"license":"MIT","_id":"@blopai/browser-harness@0.1.5","maintainers":[{"name":"hananinas","email":"hanani.nas@gmail.com"}],"homepage":"https://github.com/blop-oss/browser-harness#readme","bugs":{"url":"https://github.com/blop-oss/browser-harness/issues"},"bin":{"blop-browser":"dist/cli.js"},"dist":{"shasum":"fcc8aec03212f4114da633f9a91b375f1910448e","tarball":"https://registry.npmjs.org/@blopai/browser-harness/-/browser-harness-0.1.5.tgz","fileCount":87,"integrity":"sha512-yElFlJOIbVPxPF8gYcHZvhFyFQL9PUhZLNrl+xgJ67ahsD2ydqkFBph0ntxeJ+t4UHB15eTzUbvaKemld+/jQA==","signatures":[{"sig":"MEYCIQCljKfBJzNP0jZSBaQUgToBngiFOJle/AwaTxLiCpvSZQIhAJfdpaD9jDz/YWDVf1tFba3GXipW0C11FziCw056wUTF","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@blopai%2fbrowser-harness@0.1.5","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":465067},"type":"module","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"a49354f62c8ebe772d2f66132186ae45de79d09e","scripts":{"test":"bun run build && bun test test/browser test/session test/benchmarks test/cli","build":"tsc","clean":"rm -rf dist","test:cli":"bun test test/cli","typecheck":"tsc --noEmit","test:browser":"bun test test/browser","test:session":"bun test test/session","prepublishOnly":"npm run clean && npm run build","test:benchmarks":"bun test test/benchmarks"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:189fe6e5-4815-49f6-9e84-e005c07cc06f"}},"repository":{"url":"git+https://github.com/blop-oss/browser-harness.git","type":"git"},"_npmVersion":"11.5.1","description":"Playwright browser harness for AI agents: controlled native tools, sessions, screencast, and optional Docker browser sandbox.","directories":{},"_nodeVersion":"22.14.0","dependencies":{"playwright":"^1.61.1","camoufox-js":"0.11.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.8.3","@types/node":"^22.15.18"},"_npmOperationalInternal":{"tmp":"tmp/browser-harness_0.1.5_1784907595164_0.22296287896897127","host":"s3://npm-registry-packages-npm-production"}},"0.1.6":{"name":"@blopai/browser-harness","version":"0.1.6","keywords":["ai-agents","agent-tools","browser-automation","browser-cli","camoufox","claude-code","coding-agents","codex","llm-tools","opencode","playwright","typescript","web-automation","cdp","browser"],"license":"MIT","_id":"@blopai/browser-harness@0.1.6","maintainers":[{"name":"hananinas","email":"hanani.nas@gmail.com"}],"homepage":"https://github.com/blop-oss/browser-harness#readme","bugs":{"url":"https://github.com/blop-oss/browser-harness/issues"},"bin":{"blop-browser":"dist/cli.js"},"dist":{"shasum":"f494ade524e85b496ecbe2e3d250045dcb29b81f","tarball":"https://registry.npmjs.org/@blopai/browser-harness/-/browser-harness-0.1.6.tgz","fileCount":100,"integrity":"sha512-ct4TXeUwHYdJzYB0tmCp5pRnAXSvSs++NUe8uVJAD81mIA8RAsR8AbZDw4A87SgnHWDq/J086hHwfmJoDiHtlA==","signatures":[{"sig":"MEUCIBUkUH8h8irWCGcbywlN8x2k1RjpnWOcHZcLz5Cl1ALtAiEAq9EJ2FDSrITuWyl3yKYAC12YPfsm8bklFPFhrQWKx/M=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@blopai%2fbrowser-harness@0.1.6","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":532510},"type":"module","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"84aac985947f8fbfaeac2589ccafe009317ee3c4","scripts":{"lint":"oxlint src test benchmarks/mind2web scripts --deny-warnings","test":"bun run build && bun test test/browser test/session test/benchmarks test/cli","build":"tsc","clean":"rm -rf dist","format":"prettier --write '*.md' 'docs/**/*.md' '.github/**/*.{md,yml,yaml}' 'benchmarks/*.md' 'benchmarks/*.json' 'benchmarks/mind2web/*.md' 'scripts/**/*.mjs' package.json","test:cli":"bun test test/cli","typecheck":"tsc --noEmit","check:links":"node scripts/check-markdown-links.mjs","format:check":"prettier --check '*.md' 'docs/**/*.md' '.github/**/*.{md,yml,yaml}' 'benchmarks/*.md' 'benchmarks/*.json' 'benchmarks/mind2web/*.md' 'scripts/**/*.mjs' package.json","test:browser":"bun test test/browser","test:session":"bun test test/session","prepublishOnly":"npm run clean && npm run build","test:benchmarks":"bun test test/benchmarks","test:benchmark-smoke":"bun test test/benchmarks/mind2web.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:189fe6e5-4815-49f6-9e84-e005c07cc06f"}},"repository":{"url":"git+https://github.com/blop-oss/browser-harness.git","type":"git"},"_npmVersion":"11.5.1","description":"Blop Browser: browser infrastructure for coding agents with controlled tools, persistent sessions, CDP reuse, and optional Camoufox.","directories":{},"_nodeVersion":"22.14.0","dependencies":{"playwright":"^1.61.1","camoufox-js":"0.11.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"oxlint":"^1.78.0","prettier":"^3.9.6","typescript":"^5.8.3","@types/node":"^22.15.18"},"_npmOperationalInternal":{"tmp":"tmp/browser-harness_0.1.6_1786614196845_0.02822525098419959","host":"s3://npm-registry-packages-npm-production"}},"0.1.7":{"name":"@blopai/browser-harness","version":"0.1.7","keywords":["ai-agents","agent-tools","browser-automation","browser-cli","camoufox","claude-code","coding-agents","codex","llm-tools","opencode","playwright","typescript","web-automation","cdp","browser"],"license":"MIT","_id":"@blopai/browser-harness@0.1.7","maintainers":[{"name":"hananinas","email":"hanani.nas@gmail.com"}],"homepage":"https://github.com/blop-oss/blop-browser#readme","bugs":{"url":"https://github.com/blop-oss/blop-browser/issues"},"bin":{"blop-browser":"dist/cli.js"},"dist":{"shasum":"553abb4da34134c887fb13f5b10f05599e29a4c3","tarball":"https://registry.npmjs.org/@blopai/browser-harness/-/browser-harness-0.1.7.tgz","fileCount":100,"integrity":"sha512-62qynXZqMvReF7z2K5O3Jn1HTvBWWmemygQfE3P2kRz/2EZ+9x7onc1VeEYCn5aYzAE7FdAF3Khdry21HVESjQ==","signatures":[{"sig":"MEQCIBZm4z1vPwnGTt2hPJXDOHHvIiqldVbA8n5yKm+JLsDRAiAsKOn3UYxii/nYd3Jnj7YTBkNP54nI6zUcUvz71wLDmA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@blopai%2fbrowser-harness@0.1.7","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":532479},"type":"module","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"d0b2fd533941ff7870a74df4b814dd45ce269b56","scripts":{"lint":"oxlint src test benchmarks/mind2web scripts --deny-warnings","test":"bun run build && bun test test/browser test/session test/benchmarks test/cli","build":"tsc","clean":"rm -rf dist","format":"prettier --write '*.md' 'docs/**/*.md' '.github/**/*.{md,yml,yaml}' 'benchmarks/*.md' 'benchmarks/*.json' 'benchmarks/mind2web/*.md' 'scripts/**/*.mjs' package.json","test:cli":"bun test test/cli","typecheck":"tsc --noEmit","check:links":"node scripts/check-markdown-links.mjs","format:check":"prettier --check '*.md' 'docs/**/*.md' '.github/**/*.{md,yml,yaml}' 'benchmarks/*.md' 'benchmarks/*.json' 'benchmarks/mind2web/*.md' 'scripts/**/*.mjs' package.json","test:browser":"bun test test/browser","test:session":"bun test test/session","prepublishOnly":"npm run clean && npm run build","test:benchmarks":"bun test test/benchmarks","test:benchmark-smoke":"bun test test/benchmarks/mind2web.test.ts"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:46048112-6125-4255-b720-ade8ee0a7dbc"}},"repository":{"url":"git+https://github.com/blop-oss/blop-browser.git","type":"git"},"_npmVersion":"11.5.1","description":"Blop Browser: browser infrastructure for coding agents with controlled tools, persistent sessions, CDP reuse, and optional Camoufox.","directories":{},"_nodeVersion":"22.14.0","dependencies":{"playwright":"^1.61.1","camoufox-js":"0.11.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"oxlint":"^1.78.0","prettier":"^3.9.6","typescript":"^5.8.3","@types/node":"^22.15.18"},"_npmOperationalInternal":{"tmp":"tmp/browser-harness_0.1.7_1786615907428_0.5512412597219434","host":"s3://npm-registry-packages-npm-production"}},"0.1.8":{"name":"@blopai/browser-harness","version":"0.1.8","keywords":["ai-agents","agent-tools","browser-automation","browser-cli","camoufox","claude-code","coding-agents","codex","llm-tools","opencode","playwright","typescript","web-automation","cdp","browser"],"license":"MIT","_id":"@blopai/browser-harness@0.1.8","maintainers":[{"name":"hananinas","email":"hanani.nas@gmail.com"}],"homepage":"https://github.com/blop-oss/blop-browser#readme","bugs":{"url":"https://github.com/blop-oss/blop-browser/issues"},"bin":{"blop-browser":"dist/cli.js"},"dist":{"shasum":"df28c14b21ec16402ce73b53ea8cca71cda873dd","tarball":"https://registry.npmjs.org/@blopai/browser-harness/-/browser-harness-0.1.8.tgz","fileCount":158,"integrity":"sha512-di82nCevTRZxSbX6u1xC25nyEH1VXj6RmXPSigQkTkY8I9pnyglmTG7VSrfBoGs7TtTGvKutqoH3n1E1DyXPTQ==","signatures":[{"sig":"MEUCIQDlRvAGbEvFpa0S7ZcdTZaEnWVuBk8PHzvtDWZyfoPv4wIgL+63+OUlxGRqYWTC0rzwZUMMhTSrTFar09pfbvGEXog=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@blopai%2fbrowser-harness@0.1.8","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1308431},"type":"module","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"b30d8afa8986b609d168727afef964f4ada61b2d","scripts":{"lint":"oxlint src test benchmarks/mind2web benchmarks/detection benchmarks/session-metrics scripts --deny-warnings","test":"bun run build && bun test test/browser test/session test/benchmarks test/cli","build":"tsc","clean":"rm -rf dist","format":"prettier --write '*.md' 'docs/**/*.md' '.github/**/*.{md,yml,yaml}' 'benchmarks/*.md' 'benchmarks/*.json' 'benchmarks/mind2web/*.md' 'benchmarks/detection/*.{md,json,mjs}' 'benchmarks/session-metrics/*.{md,json,mjs}' 'scripts/**/*.mjs' package.json","test:cli":"bun test test/cli","typecheck":"tsc --noEmit","check:links":"node scripts/check-markdown-links.mjs","check:claims":"node scripts/check-public-claims.mjs","demo:privacy":"bun run build && node scripts/demo-privacy-data-flows.mjs","format:check":"prettier --check '*.md' 'docs/**/*.md' '.github/**/*.{md,yml,yaml}' 'benchmarks/*.md' 'benchmarks/*.json' 'benchmarks/mind2web/*.md' 'benchmarks/detection/*.{md,json,mjs}' 'benchmarks/session-metrics/*.{md,json,mjs}' 'scripts/**/*.mjs' package.json","test:browser":"bun test test/browser","test:session":"bun test test/session","check:privacy":"node scripts/check-privacy-data-flows.mjs","demo:takeover":"bun run build && node scripts/demo-human-takeover.mjs","prepublishOnly":"npm run clean && npm run build","test:benchmarks":"bun test test/benchmarks","check:comparison":"node scripts/check-comparison-matrix.mjs","demo:positioning":"bun run build && node scripts/demo-positioning-proof.mjs","check:positioning":"node scripts/check-positioning-proof.mjs","check:availability":"node scripts/check-capability-availability.mjs","benchmark:detection":"node benchmarks/detection/run.mjs","check:acceptable-use":"node scripts/check-acceptable-use.mjs","test:benchmark-smoke":"bun test test/benchmarks/mind2web.test.ts","check:security-policy":"node scripts/check-security-policy.mjs","benchmark:session-metrics":"node benchmarks/session-metrics/run.mjs"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:46048112-6125-4255-b720-ade8ee0a7dbc"}},"repository":{"url":"git+https://github.com/blop-oss/blop-browser.git","type":"git"},"_npmVersion":"11.5.1","description":"Local browser tools and session infrastructure for agent hosts; no hosted service and no model or agent loop.","directories":{},"_nodeVersion":"22.14.0","dependencies":{"playwright":"^1.61.1","camoufox-js":"0.11.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"oxlint":"^1.78.0","prettier":"^3.9.6","typescript":"^5.8.3","@types/node":"^22.15.18"},"_npmOperationalInternal":{"tmp":"tmp/browser-harness_0.1.8_1786699558697_0.7915274066604951","host":"s3://npm-registry-packages-npm-production"}},"0.1.9":{"name":"@blopai/browser-harness","version":"0.1.9","keywords":["ai-agents","agent-tools","browser-automation","browser-cli","camoufox","claude-code","coding-agents","codex","llm-tools","opencode","playwright","typescript","web-automation","cdp","browser"],"license":"MIT","_id":"@blopai/browser-harness@0.1.9","maintainers":[{"name":"hananinas","email":"hanani.nas@gmail.com"}],"homepage":"https://github.com/blop-oss/blop-browser#readme","bugs":{"url":"https://github.com/blop-oss/blop-browser/issues"},"bin":{"blop-browser":"dist/cli.js"},"dist":{"shasum":"87e67e5581449bdf15497cce84d61799e4a8eb64","tarball":"https://registry.npmjs.org/@blopai/browser-harness/-/browser-harness-0.1.9.tgz","fileCount":165,"integrity":"sha512-y0dTDphtmeU5epsrfPp468ZjfUPLp5tqecVwxR3FK+mUiVJcoiw7O20r83rd5m9UY1t7YdTtIYE+c6ZsblldjA==","signatures":[{"sig":"MEUCIQCYX2tmJnNtgFp46tB5yDkmUojjVsDcNarpwkZ/P4OyQAIgMD5eWxfXmn0hlOoCr7EKsrbd7pJHTbTidl1hGsoENe4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@blopai%2fbrowser-harness@0.1.9","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":1346039},"type":"module","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"gitHead":"dd53aa0391ef8b5b308c6bc16c778cebf9461e4c","scripts":{"lint":"oxlint src test benchmarks/mind2web benchmarks/detection benchmarks/session-metrics scripts --deny-warnings","test":"bun run build && bun test test/browser test/session test/benchmarks test/cli","build":"tsc","clean":"rm -rf dist","format":"prettier --write '*.md' 'docs/**/*.md' '.github/**/*.{md,yml,yaml}' 'benchmarks/*.md' 'benchmarks/*.json' 'benchmarks/mind2web/*.md' 'benchmarks/detection/*.{md,json,mjs}' 'benchmarks/session-metrics/*.{md,json,mjs}' 'scripts/**/*.mjs' package.json","test:cli":"bun test test/cli","typecheck":"tsc --noEmit","check:links":"node scripts/check-markdown-links.mjs","check:claims":"node scripts/check-public-claims.mjs","demo:privacy":"bun run build && node scripts/demo-privacy-data-flows.mjs","format:check":"prettier --check '*.md' 'docs/**/*.md' '.github/**/*.{md,yml,yaml}' 'benchmarks/*.md' 'benchmarks/*.json' 'benchmarks/mind2web/*.md' 'benchmarks/detection/*.{md,json,mjs}' 'benchmarks/session-metrics/*.{md,json,mjs}' 'scripts/**/*.mjs' package.json","test:browser":"bun test test/browser","test:session":"bun test test/session","check:privacy":"node scripts/check-privacy-data-flows.mjs","demo:takeover":"bun run build && node scripts/demo-human-takeover.mjs","prepublishOnly":"npm run clean && npm run build","test:benchmarks":"bun test test/benchmarks","check:comparison":"node scripts/check-comparison-matrix.mjs","demo:positioning":"bun run build && node scripts/demo-positioning-proof.mjs","check:positioning":"node scripts/check-positioning-proof.mjs","check:availability":"node scripts/check-capability-availability.mjs","benchmark:detection":"node benchmarks/detection/run.mjs","check:acceptable-use":"node scripts/check-acceptable-use.mjs","test:benchmark-smoke":"bun test test/benchmarks/mind2web.test.ts","check:security-policy":"node scripts/check-security-policy.mjs","benchmark:session-metrics":"node benchmarks/session-metrics/run.mjs"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:46048112-6125-4255-b720-ade8ee0a7dbc"}},"repository":{"url":"git+https://github.com/blop-oss/blop-browser.git","type":"git"},"_npmVersion":"11.5.1","description":"Local browser tools and session infrastructure for agent hosts; no hosted service and no model or agent loop.","directories":{},"_nodeVersion":"22.14.0","dependencies":{"playwright":"^1.61.1","camoufox-js":"0.11.1"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"oxlint":"^1.78.0","prettier":"^3.9.6","typescript":"^5.8.3","@types/node":"^22.15.18"},"_npmOperationalInternal":{"tmp":"tmp/browser-harness_0.1.9_1786700791331_0.8110150586215321","host":"s3://npm-registry-packages-npm-production"}},"0.1.10":{"name":"@blopai/browser-harness","version":"0.1.10","description":"Local browser tools and session infrastructure for agent hosts; no hosted service and no model or agent loop.","license":"MIT","type":"module","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"}},"bin":{"blop-browser":"dist/cli.js"},"keywords":["ai-agents","agent-tools","browser-automation","browser-cli","camoufox","claude-code","coding-agents","codex","llm-tools","opencode","playwright","typescript","web-automation","cdp","browser"],"repository":{"type":"git","url":"git+https://github.com/blop-oss/blop-browser.git"},"homepage":"https://github.com/blop-oss/blop-browser#readme","bugs":{"url":"https://github.com/blop-oss/blop-browser/issues"},"scripts":{"build":"tsc","format":"prettier --write '*.md' 'docs/**/*.md' '.github/**/*.{md,yml,yaml}' 'benchmarks/*.md' 'benchmarks/*.json' 'benchmarks/mind2web/*.md' 'benchmarks/detection/*.{md,json,mjs}' 'benchmarks/session-metrics/*.{md,json,mjs}' 'scripts/**/*.mjs' package.json","format:check":"prettier --check '*.md' 'docs/**/*.md' '.github/**/*.{md,yml,yaml}' 'benchmarks/*.md' 'benchmarks/*.json' 'benchmarks/mind2web/*.md' 'benchmarks/detection/*.{md,json,mjs}' 'benchmarks/session-metrics/*.{md,json,mjs}' 'scripts/**/*.mjs' package.json","check:links":"node scripts/check-markdown-links.mjs","check:comparison":"node scripts/check-comparison-matrix.mjs","check:positioning":"node scripts/check-positioning-proof.mjs","check:claims":"node scripts/check-public-claims.mjs","check:availability":"node scripts/check-capability-availability.mjs","check:acceptable-use":"node scripts/check-acceptable-use.mjs","check:security-policy":"node scripts/check-security-policy.mjs","check:privacy":"node scripts/check-privacy-data-flows.mjs","lint":"oxlint src test benchmarks/mind2web benchmarks/detection benchmarks/session-metrics scripts --deny-warnings","typecheck":"tsc --noEmit","test":"bun run build && bun test test/browser test/session test/benchmarks test/cli","test:browser":"bun test test/browser","test:session":"bun test test/session","test:benchmarks":"bun test test/benchmarks","benchmark:detection":"node benchmarks/detection/run.mjs","benchmark:session-metrics":"node benchmarks/session-metrics/run.mjs","test:cli":"bun test test/cli","test:benchmark-smoke":"bun test test/benchmarks/mind2web.test.ts","demo:positioning":"bun run build && node scripts/demo-positioning-proof.mjs","demo:privacy":"bun run build && node scripts/demo-privacy-data-flows.mjs","demo:takeover":"bun run build && node scripts/demo-human-takeover.mjs","clean":"rm -rf dist","prepublishOnly":"npm run clean && npm run build"},"dependencies":{"camoufox-js":"0.11.1","playwright":"^1.61.1"},"devDependencies":{"@types/node":"^22.15.18","oxlint":"^1.78.0","prettier":"^3.9.6","typescript":"^5.8.3"},"engines":{"node":">=22"},"publishConfig":{"access":"public"},"_id":"@blopai/browser-harness@0.1.10","gitHead":"2a52917a79a61b9a2056dda9473457bc05416d58","_nodeVersion":"22.14.0","_npmVersion":"11.5.1","dist":{"integrity":"sha512-oAS5u7vQsgtChsyiOnA8DPWATcx3f/K09X0xNaL6xTmmEwkw+5c0PpElkQIUFxQTWhZ1lJKLw/tBAuuLv9y+dQ==","shasum":"815478b2cca429fbc7e67c27152bd9e8a7d957df","tarball":"https://registry.npmjs.org/@blopai/browser-harness/-/browser-harness-0.1.10.tgz","fileCount":165,"unpackedSize":1354054,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@blopai%2fbrowser-harness@0.1.10","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCWXhwLSIHf0uiVUHF6F+Rqtzv90PidJP3+GEOZtdFtpAIgbWdbNDKSEU6Nc8vE+zAiUXv9uABugm8I0GOSt1Zjyrw="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:46048112-6125-4255-b720-ade8ee0a7dbc"}},"directories":{},"maintainers":[{"name":"hananinas","email":"hanani.nas@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/browser-harness_0.1.10_1786737646298_0.9027558275950534"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-23T16:19:49.140Z","modified":"2026-08-14T20:00:46.833Z","0.1.0":"2026-07-23T16:19:49.408Z","0.1.1":"2026-07-23T16:30:04.673Z","0.1.2":"2026-07-23T16:58:55.105Z","0.1.3":"2026-07-23T19:20:18.851Z","0.1.4":"2026-07-24T15:11:49.535Z","0.1.5":"2026-07-24T15:39:55.318Z","0.1.6":"2026-08-13T09:43:16.983Z","0.1.7":"2026-08-13T10:11:47.562Z","0.1.8":"2026-08-14T09:25:58.858Z","0.1.9":"2026-08-14T09:46:31.477Z","0.1.10":"2026-08-14T20:00:46.446Z"},"bugs":{"url":"https://github.com/blop-oss/blop-browser/issues"},"license":"MIT","homepage":"https://github.com/blop-oss/blop-browser#readme","keywords":["ai-agents","agent-tools","browser-automation","browser-cli","camoufox","claude-code","coding-agents","codex","llm-tools","opencode","playwright","typescript","web-automation","cdp","browser"],"repository":{"type":"git","url":"git+https://github.com/blop-oss/blop-browser.git"},"description":"Local browser tools and session infrastructure for agent hosts; no hosted service and no model or agent loop.","maintainers":[{"name":"hananinas","email":"hanani.nas@gmail.com"}],"readme":"<p align=\"center\">\n  <img src=\"logo.svg\" width=\"120\" alt=\"Blop Browser logo\" />\n</p>\n\n# Blop Browser\n\n**Browser infrastructure for coding agents.**\n\nRun browser sessions through a controlled CLI with headless Chromium, explicit\nexisting-Chrome attachment, or optional Camoufox. Blop Browser integrates with\nCodex, Claude Code, OpenCode, and custom agent hosts.\n\nBlop Browser is browser infrastructure, not a complete browser agent. It has no\nmodel, planner, or autonomous agent loop; your host owns orchestration and\napproval decisions. Review the [known limitations](docs/known-limitations.md)\nand [privacy and data-flow contract](PRIVACY.md) before choosing it for a\nworkflow.\n\nBlop Browser has no hosted free or paid tier. Commands and APIs run in\ninfrastructure you operate or in a browser you explicitly attach. The separate\nBlop QA product is not a hosting tier for this package. Review the\n[capability availability](docs/capability-availability.md) for the local\ncontract and the dated official-source audit.\n\nUse Blop Browser only on websites, accounts, and data you own or are authorized\nto access. Read the [acceptable-use policy](ACCEPTABLE_USE.md) before setup.\n\n```bash\nnpm i -g @blopai/browser-harness\nblop-browser open https://example.com\nblop-browser snapshot\n```\n\n[![CI](https://github.com/blop-oss/blop-browser/actions/workflows/ci.yml/badge.svg)](https://github.com/blop-oss/blop-browser/actions/workflows/ci.yml)\n[![npm version](https://img.shields.io/npm/v/@blopai/browser-harness)](https://www.npmjs.com/package/@blopai/browser-harness)\n[![npm downloads](https://img.shields.io/npm/dm/@blopai/browser-harness)](https://www.npmjs.com/package/@blopai/browser-harness)\n[![Node.js 22+](https://img.shields.io/badge/node-%3E%3D22-339933?logo=node.js&logoColor=white)](package.json)\n[![license: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n\nThe first command starts a local daemon. Later commands in the same named\nsession reuse its browser, cookies, page state, tabs, action trail, and current\nsemantic element references.\n\nBlop Browser differs from general-purpose browser automation by combining:\n\n- Controlled, bounded browser tools instead of arbitrary page-script or CDP\n  execution.\n- Persistent or disposable managed storage separated by `--session` name.\n- Existing Chrome and authorized profile reuse over CDP.\n- An explicit automation-to-human control handoff for active headed or attached\n  sessions.\n- Optional anti-bot mode, off by default, that launches Camoufox to change\n  browser-observable fingerprints.\n- A public TypeScript API for embedding the same tools in your own agent host.\n- Warm Playwright Chromium and Camoufox Docker browser services.\n- An agent-neutral CLI, machine-readable JSON output, and an installable agent\n  skill.\n\nThe published npm package is `@blopai/browser-harness`, and its executable is\n`blop-browser`. Current imports, commands, configuration variables, and\nrepository links use those compatibility names.\n\n## Demo\n\nA real demo has not been recorded yet. The repository intentionally does not\nembed a fabricated or broken media asset.\n\nThe [demo recording guide](docs/demo-recording.md) provides a shot-by-shot,\nreproducible script for the bundled local fixture. It covers taking a semantic\nsnapshot, interacting through refs, proving that state persists between CLI\ncommands, and displaying the live screencast dashboard. Final media belongs in\n`docs/assets/demo/` after it has been recorded and reviewed.\n\n## Install\n\nBlop Browser requires Node.js 22 or newer. It uses an installed Chrome or\nChromium when available; you can also install Playwright Chromium or Camoufox.\nUse each mode only for workflows permitted by the\n[acceptable-use policy](ACCEPTABLE_USE.md).\n\n```bash\nnpm install --global @blopai/browser-harness\nblop-browser doctor\n```\n\nIf `doctor` doesn't find a Chromium browser, install Playwright Chromium:\n\n```bash\nnpx playwright install chromium\n```\n\nInstall the optional agent skill with Vercel's skills CLI:\n\n```bash\nnpx skills add blop-oss/blop-browser --skill browser-harness\n```\n\nAdd `-g` for a global skill install, or use `-a opencode`, `-a claude-code`, or\n`-a codex` to target one agent. The skill identifier stays `browser-harness` for\ncompatibility.\n\n<details>\n<summary><strong>Install through your coding agent</strong></summary>\n\nPaste this prompt into Codex, Claude Code, OpenCode, or another coding agent:\n\n```text\nInstall the Blop Browser skill and set up the blop-browser CLI:\n\n1. Read https://github.com/blop-oss/blop-browser/blob/master/ACCEPTABLE_USE.md\n   and confirm this setup is for websites and accounts I own or am authorized\n   to automate.\n2. Run: npx skills add blop-oss/blop-browser --skill browser-harness -g\n3. Run: npm install --global @blopai/browser-harness\n4. Run: blop-browser doctor --json\n5. Read the doctor output. If configuration.mode is null, ask me how I want to\n   use the browser and then run the matching config command:\n   - Headless Chromium (agents/CI): blop-browser config --mode chromium-headless\n   - Visible Chromium (local debugging): blop-browser config --mode chromium-headed\n   - Existing Chrome over CDP: blop-browser config --mode chrome-cdp --cdp-endpoint http://127.0.0.1:9222\n    - Camoufox headless: blop-browser config --mode camoufox-headless\n    - Camoufox visible: blop-browser config --mode camoufox-headed\n    - Optional anti-bot: blop-browser config --anti-bot on\n6. If the mode is managed Chromium or Camoufox, confirm the setup with:\n   blop-browser open https://example.com && blop-browser snapshot\n7. If the mode is chrome-cdp, get my explicit approval to access that Chrome\n   profile, then confirm with:\n   blop-browser --attach-existing open https://example.com && blop-browser snapshot\n```\n\n</details>\n\nInteractive terminals check the npm registry at most once every 24 hours and\nask before installing a newer `@blopai/browser-harness`. This is not telemetry.\nDisable the check with `BLOP_BROWSER_UPDATE_CHECK=off`.\n\n```bash\nblop-browser update\nblop-browser update --json\n```\n\n`--json` reports the current and latest versions without installing. Approving\nan update, or passing `--install`, runs\n`npm install --global @blopai/browser-harness` and overwrites any existing\n`browser-harness` skill copies in the usual user and project skill directories.\nIt does not create a skill install that was not already present.\n\n## Choose a browser mode\n\nThe first interactive browser command opens `blop-browser config` when no mode\nhas been saved. The choice is stored in the platform configuration directory.\nNon-interactive agents and CI default to headless Chromium.\n\n```bash\nblop-browser config --mode chromium-headless\nblop-browser config --mode chromium-headed\nblop-browser config --mode chrome-cdp \\\n  --cdp-endpoint http://127.0.0.1:9222\nblop-browser config --mode camoufox-headless\nblop-browser config --mode camoufox-headed\nblop-browser config --anti-bot on\nblop-browser config --anti-bot off\n```\n\nAn explicit `--browser`, `--cdp-endpoint`, `--profile`, `--headless`,\n`--headed`, or `--anti-bot` option overrides the saved default for a new\nsession. Environment variables continue to override saved configuration. A CDP\nendpoint selects the target, but it doesn't authorize profile access: the\ncommand that starts the attachment must also include `--attach-existing`.\n\nAnti-bot mode is off by default. Enabling it launches Camoufox for authorized\nworkflows that need reduced automation signals. Choose the backend from the\nworkflow, not from a promise that a site will accept the session:\n\n- Use managed Chromium for deterministic testing of local fixtures, staging\n  environments, and applications you control.\n- Use a dedicated Chrome profile over CDP when an authorized workflow requires\n  its real Chrome state. Profile history, extensions, login state, and the\n  installed Chrome version make CDP runs less controlled as comparisons.\n- Enable optional anti-bot mode, or select Camoufox directly, only for\n  authorized workflows. Its generated fingerprint can vary between otherwise\n  identical launches. This does not establish anonymity or avoidance of site\n  controls.\n\nThe [local backend signal protocol](benchmarks/detection/README.md) records\nversions, launch constraints, bounded browser-observable signals, failures, and\nlimitations across three fresh-profile repetitions. It isn't a detection score\nor a bot-protection bypass benchmark.\n\n## Use the CLI\n\nUse distinct session names to give concurrent agents or workflows separate\nmanaged browser storage. Each command targets the same named daemon until you\nclose it or its idle timeout expires.\n\n```bash\nblop-browser --session docs-review open https://example.com\nblop-browser --session docs-review snapshot\nblop-browser --session docs-review click e6\nblop-browser --session docs-review screenshot docs-review --full-page\nblop-browser --session docs-review close\n```\n\nManaged sessions use a dedicated persistent profile and downloads directory for\neach session name. `close` stops the browser but keeps that state. Inspect the\nreported scope before handling authenticated data:\n\n```bash\nblop-browser --session checkout status --json\n```\n\nThe `sessionScope` result reports the profile mode, storage scope, profile,\ndownloads and artifact directories, local owner, expiry, and whether the\nprofile is managed by Blop Browser. The `privacy` result separately reports\nlocal or attached mode, first-party harness telemetry (`off`), CLI recording\nstates, the daemon log, and distinct local, managed-browser, and\nexternal-browser retention. A newly started daemon returns the same object at\nthe top of its first JSON response; human output prints a concise version to\nstderr. See [privacy and data flows](PRIVACY.md) before handling sensitive\npages.\n\nUse a disposable profile when state must expire with the daemon:\n\n```bash\nblop-browser --session review --profile disposable open https://example.com\nblop-browser --session review close\n```\n\nDisposable profile, download, artifact, and daemon-log state is removed on\nexplicit close or idle shutdown. List retained session metadata without\nreading profile contents, then delete one validated session through the\ndiscoverable lifecycle commands:\n\n```bash\nblop-browser data list --json\nblop-browser data delete checkout\n```\n\n`data delete checkout` is the strict alias of:\n\n```bash\nblop-browser --session checkout destroy\n```\n\n`destroy` closes an active managed session before deleting its state. For an\nattached Chrome session, it disconnects and removes only Blop Browser's managed\nartifacts; it does not delete the external Chrome profile. Neither command\nremoves global configuration, browser caches, Docker resources, website data,\nor host/provider records, and filesystem removal is not secure erasure.\n\nUse `--json` for a machine-readable response envelope:\n\n```bash\nblop-browser --session docs-review snapshot --json\n```\n\n```json\n{\n  \"ok\": true,\n  \"result\": {\n    \"content\": \"...\",\n    \"contentBoundary\": {\n      \"source\": \"browser\",\n      \"trust\": \"untrusted\",\n      \"url\": \"https://example.com/\"\n    },\n    \"metadata\": {}\n  }\n}\n```\n\nEvery tool result has a `contentBoundary`. Direct page observations use\n`source: \"browser\"`; action results that combine harness text with page state\nuse `source: \"mixed\"`; and messages generated only by the harness use\n`source: \"harness\"`. Lifecycle results that echo host input use\n`source: \"caller\"`. Browser, mixed, and caller results are always\n`trust: \"untrusted\"`. Model images carry their own untrusted browser boundary.\nPreserve these fields when adapting tools to a model SDK, and pass untrusted\ncontent as tool data—not as system, developer, or host instructions.\n\nThe CLI exposes every native tool through a self-describing interface:\n\n```bash\nblop-browser tools\nblop-browser describe browser_click\nblop-browser call browser_click --input '{\"target\":{\"ref\":\"e1\"}}'\n```\n\nRun `blop-browser --help` for the complete command list.\n\nExport the bounded action trace as a human timeline or JSON. Persistent\nsessions retain the latest complete trace after close or idle shutdown, until\nyou run `destroy`:\n\n```bash\nblop-browser --session docs-review trace\nblop-browser --session docs-review trace --json\n```\n\nTrace events include ordered timestamps, redacted inputs and URLs, target refs,\nsuccesses and failures, approval metadata, content boundaries, and available\nscreenshot or screencast positions. See the\n[action trace contract, redaction limits, and retention rules](docs/action-traces.md)\nbefore storing or sharing an export.\n\nExport bounded aggregate session metrics as text or JSON. Persistent sessions\nretain the latest aggregate across close and resume until `destroy`:\n\n```bash\nblop-browser --session docs-review metrics\nblop-browser --session docs-review metrics --json\n```\n\nMetrics report command outcomes, snapshots, explicit harness retries,\napprovals, durations, and exact Unicode code-point and UTF-8 payload volume.\nThey retain no payload content and report provider token counts as unavailable,\nnot as character-based estimates. Read the\n[session metrics contract and retention rules](docs/session-metrics.md) before\nusing an aggregate as evidence.\n\n## Hand control to a person\n\nPause harness automation when a person needs to handle a challenge or a\nsensitive step in an active headed managed browser or an attached browser. A\nmanaged headless session has no browser access path for a person, so a takeover\nrequest fails before pausing it.\n\n```bash\nblop-browser config --mode chromium-headed\nblop-browser --session review open https://example.com\nblop-browser --session review takeover request challenge \\\n  --message \"Complete the visible challenge.\" --json\nblop-browser --session review takeover control REQUEST_ID --json\n# The person uses the reported managed window.\nblop-browser --session review takeover resume REQUEST_ID LEASE_ID \\\n  --outcome completed --json\n```\n\nFor an attached browser, the response identifies the configured attached\nbrowser. The CLI cannot verify that a remote or local CDP endpoint is visible\nor reachable by the intended person. The host or operator must provide the\nactual browser access, notification, and user interface.\n\n`takeover request` changes the state from `automation` to `pausing`, rejects new\nharness commands before any `Page` access, waits for already admitted commands,\nand then reports `paused`. `takeover control` returns a lease and changes the\nstate to `human-control`. `takeover resume` requires the matching request and\nlease IDs before returning to `automation`. These IDs serialize callers; they\nare not authentication, authorization, or evidence that a person acted. Any\ncaller authenticated to the daemon can invoke the transition commands.\n\nWhile automation is paused, `status --json` returns the cached pre-pause URL\nand title with `pageState: \"cached\"`. Page scripts and network activity continue,\nand page JavaScript or an external CDP client can still race the person. Pause\nand resume invalidate all semantic refs, so take a new snapshot before the next\nagent action. If the person closes the active page, leave another tracked page\nopen for the harness to select after resume; if none remains, the next tool call\nreturns a recorded structured failure.\n\nEmbedding hosts can use the same framework-neutral controller and transition\ncallback:\n\n```ts\nimport {\n  createBrowserControlSession,\n  createBrowserTools,\n} from \"@blopai/browser-harness\";\n\nconst control = createBrowserControlSession({\n  onTransition: (transition) => hostLifecycleSink(transition),\n});\nconst tools = await createBrowserTools({\n  // ...page, action, artifact, and finish-state options\n  control,\n});\n\nconst paused = await control.requestTakeover({\n  reason: \"sensitive-step\",\n  message: \"Enter the account recovery value.\",\n});\nconst lease = control.takeControl({ requestId: paused.requestId! });\n// The host exposes the browser and waits for its operator workflow here.\ncontrol.resumeAutomation({\n  requestId: lease.requestId,\n  leaseId: lease.leaseId,\n  outcome: \"completed\",\n});\n```\n\nTransition callback failures are bounded in `control.status()` and don't roll\nback or retry a transition. The action trace records pause, acquisition, and\nresume in order, redacts the optional message, and never stores the lease.\nSemantic snapshots conservatively mask values from password fields and\ncredential-like inputs, textareas, and editable regions. This masking is not\ndata-loss prevention: screenshots, explicit extraction, arbitrary rendered\ntext, browser logs, and network activity can still expose sensitive data.\n\nRun the bundled loopback-only automated ownership proof against the built\npackage:\n\n```bash\nbun run demo:takeover\n```\n\nIt verifies command draining, concurrent rejection, resume, stale-ref\ninvalidation, redaction, and ordered trace transitions. It does not provide or\ntest a host UI, notification delivery, human identity, or proof that a person\nacted.\n\n## Connect to existing Chrome\n\nAttach over CDP to reuse an existing Chrome profile, cookies, and open tabs.\nStart Chrome with remote debugging bound to localhost and a dedicated profile\ndirectory:\n\n```bash\ngoogle-chrome \\\n  --remote-debugging-address=127.0.0.1 \\\n  --remote-debugging-port=9222 \\\n  --user-data-dir=/tmp/blop-chrome\n\nblop-browser --session chrome \\\n  --attach-existing \\\n  --cdp-endpoint http://127.0.0.1:9222 snapshot\nblop-browser --session chrome open https://example.com\nblop-browser --session chrome close\n```\n\nThe first command attaches to Chrome's default context and most recently opened\ntab. Later commands reuse that connection without repeating `--cdp-endpoint`.\nClosing Blop Browser disconnects from Chrome without closing Chrome itself.\n\nKeep the debugging port on localhost. A CDP endpoint grants full control over\nthat Chrome profile. Never infer permission from a saved configuration or\nenvironment variable. You can set `BLOP_BROWSER_CDP_ENDPOINT` instead of\npassing the endpoint, but the first command must still include\n`--attach-existing`. Attach only to a dedicated profile and accounts you are\nauthorized to control; CDP access doesn't grant permission to automate a\nwebsite.\n\nStatus and doctor output reduce a CDP URL to its scheme, host, and effective\nport; even that host can be sensitive. The owner-only global configuration\nretains the full endpoint needed to reconnect. Browser control, input, uploads,\npage state, and screenshots cross a remote CDP transport, while the attached\nprofile and remote-side logs remain outside harness deletion.\n\n## Use Camoufox\n\nCamoufox is an optional Firefox-based browser that changes browser-observable\nfingerprint characteristics. Chromium remains the default, and anti-bot mode\nstays off until you enable it. Use Chromium for deterministic testing of\napplications you control.\n\n```bash\nblop-browser install camoufox\nblop-browser config --anti-bot on\nblop-browser --session authorized-app \\\n  --anti-bot open https://staging.example.com\n```\n\n`--anti-bot`, `--anti-bot on`, `BLOP_BROWSER_ANTI_BOT=on`, and\n`blop-browser config --anti-bot on` all select Camoufox. `--anti-bot off`\nreturns later sessions to Chromium. You can also pass `--browser camoufox` for\nthe same backend.\n\nThe Camoufox browser binary is a separate third-party download. Review the\n[Camoufox project](https://github.com/daijro/camoufox) before using it in your\nenvironment. Use it only for authorized workflows. It doesn't grant permission\nto access a site, and it does not establish anonymity or avoidance of bot\nprotections and other site controls. If a site denies access you are not\nauthorized to have, stop instead of changing accounts or network routes. See\nthe [acceptable-use policy](ACCEPTABLE_USE.md).\n\n## Embed the TypeScript API\n\nInstall the existing npm package locally to embed the same bounded tools in an\nagent host.\n\n```bash\nnpm install @blopai/browser-harness\n```\n\n```ts\nimport { chromium } from \"playwright\";\nimport {\n  getBrowserSessionScope,\n  createBrowserTools,\n  createSessionMetricsRecorder,\n  createTraceRecorder,\n  type HarnessAction,\n} from \"@blopai/browser-harness\";\n\nconst sessionScope = getBrowserSessionScope(\"demo\", {\n  runtimeDirectory: \".browser-runtime\",\n});\n\nconst browser = await chromium.launch({ headless: true });\nconst page = await browser.newPage();\nconst actions: HarnessAction[] = [];\nconst traceRecorder = createTraceRecorder({\n  identity: { sessionId: \"demo\", agentId: \"accessibility-review\" },\n});\nconst sessionMetricsRecorder = createSessionMetricsRecorder();\n\nconst tools = await createBrowserTools({\n  page,\n  testId: \"demo\",\n  screenshotDir: \".harness-screenshots\",\n  actions,\n  screenshots: [],\n  finishState: { status: null, reason: null },\n  traceRecorder,\n  sessionMetricsRecorder,\n  safety: {\n    mode: \"read-only\",\n  },\n});\n\nconst goto = tools.find((tool) => tool.name === \"browser_goto\")!;\nawait goto.execute({ url: \"https://example.com\" });\nprocess.stdout.write(`${traceRecorder.timeline()}\\n`);\nprocess.stdout.write(`${sessionMetricsRecorder.json(true)}\\n`);\nawait browser.close();\n```\n\n`safety.mode: \"read-only\"` rejects pointer, keyboard, form, file-upload, and\npage-closing interactions before they reach Playwright. Navigation and\nobservation remain available so a host can inspect links and traverse public\ndocuments without granting input dispatch; this is a capability mode, not an\nHTTP safe-method guarantee. Denied attempts throw `BrowserSafetyError` and are\nstill recorded in `actions` with deterministic policy metadata.\n\nFor the standalone CLI, set `BLOP_BROWSER_READ_ONLY=1` before the command that\nstarts a named session. The daemon keeps that mode for the session, and\n`status --json` reports it as `safetyMode`:\n\n```bash\nBLOP_BROWSER_READ_ONLY=1 blop-browser --session research open https://example.com\nblop-browser --session research snapshot\n```\n\n### Enforce domain and action rules\n\nAn embedding host can freeze a static policy into each browser context. The\npolicy can combine top-level origin rules with `allow`, `deny`, or `ask`\ndecisions for harness-defined action classes:\n\n```ts\nconst tools = await createBrowserTools({\n  // ...the page, artifact, action, and finish-state options above\n  safety: {\n    domains: {\n      allow: [\"https://app.example.com\", \"https://*.assets.example.com\"],\n      deny: [\"https://admin.assets.example.com\"],\n    },\n    actions: {\n      navigation: \"allow\",\n      pointer: \"ask\",\n      keyboard: \"allow\",\n      form: \"ask\",\n      \"file-upload\": \"deny\",\n      \"page-lifecycle\": \"deny\",\n    },\n    approvalPolicy: async (request) => {\n      const approved = await approvalUi.confirm({\n        tool: request.toolName,\n        category: request.category,\n        url: request.url,\n        input: request.input,\n      });\n      return { approved, reason: approved ? undefined : \"User declined.\" };\n    },\n  },\n});\n```\n\nDomain entries must be HTTP or HTTPS origins without paths, credentials,\nqueries, or fragments. A nonempty `allow` list denies nonmatching origins, and\n`deny` takes precedence. `https://*.example.com` matches any subdomain depth,\nbut not `example.com`, `evil-example.com`, another scheme, or a nondefault\nport. Add an explicit port to a rule when you need one. Hostnames are matched\nas normalized ASCII names with DNS label boundaries.\n\nFor an existing page, the gate checks a `browser_goto` destination before its\nrequest and checks every top-level redirect hop. The same top-level gate\napplies to navigation caused by clicks, forms, or page scripts. While domain\nrules are active, the harness rejects every new-page or popup document before\nits first request, even when its requested origin is allowed. Chromium exposes\nthat request before it exposes a page that can cover later redirects, so this\nfail-closed rule prevents an allowed popup from redirecting outside policy.\n\nA domain policy is immutable for the lifetime of its `BrowserContext`. Tool\nsets that share a context must use the same rules, or must all omit rules;\nmixing policies fails setup. Nonempty domain rules currently require Chromium.\nFactory setup fails on Firefox, Camoufox, or a context whose backend can't\nenforce every top-level redirect hop. Existing host-owned context routes remain\nin the route chain.\n\nAction classes describe dispatched tool commands, not the meaning of a web\npage:\n\n- `navigation` covers `browser_goto`, `browser_reload`, `browser_go_back`, and\n  `browser_go_forward`.\n- `pointer` covers clicks, hover, and drag commands.\n- `keyboard` covers type, press, tab, focus, blur, and clear commands.\n- `form` covers check, uncheck, and select-option commands.\n- `file-upload` covers `browser_upload_file`.\n- `page-lifecycle` currently covers `browser_close_page`.\n\nViewport changes, page selection, observations, and evidence tools stay\noutside the interaction gate. A click that submits a form remains `pointer`,\nand Enter remains `keyboard`; the harness does not guess that either command\nis a submission, purchase, or message. Navigation caused by such a command\ndoes not trigger a second `navigation` approval, because its destination isn't\nknown before dispatch. Domain rules still check that top-level destination.\n\nThe callback runs only for a category whose decision is `ask`. If you supply\n`approvalPolicy` without explicit action decisions, existing non-navigation\ninteractions default to `ask`; navigation defaults to `allow` unless you\nconfigure it. Callback URLs omit query and fragment values. Text, values,\ncredentials, and file paths in `request.input` become bounded redaction\nsummaries. Page wording never changes the static category. A missing callback,\nexception, malformed result, or negative decision denies the command. A host\ndenial reason is reduced to a bounded single line before it enters an error or\naction record. Batch envelopes don't bypass the gate: each inner command is\nchecked and recorded, and nested batches are rejected.\n\nThese controls bound consequences; they do not solve prompt injection. A page\ncan mutate itself or make network requests while loading, and a GET navigation\ncan have server-side effects on a poorly designed site. Read-only mode does not\ndisable JavaScript, networking, cookies, downloads initiated by the page, or\naccess already granted to an attached profile. Domain rules cover top-level\ndocuments only; they don't filter iframes, images, scripts, fonts, fetches,\nWebSockets, service workers, or other subresources. They are not network\nisolation. The policy does not impose download, message, submission, or general\nresource rules beyond the explicit tool classes above. Use a dedicated browser\nprofile, enforce network and filesystem boundaries outside the harness, and\nrequire a human decision for consequential actions.\n\nThe standalone CLI currently exposes only read-only mode through\n`BLOP_BROWSER_READ_ONLY`. Domain rules, action decisions, and approval\ncallbacks are embedding API features; the CLI does not invent a policy or\nhuman approval workflow.\n\nThe trace API returns immutable copies and bounded JSON or human timelines.\nFailed and policy-denied actions remain visible. Read the\n[action trace documentation](docs/action-traces.md) for the complete public\ncontract and privacy limitations.\n\nThe metrics API returns immutable bounded aggregates without retaining raw\npayload content. It counts only harness-observable retries and leaves provider\ntokens `null`. Read the [session metrics documentation](docs/session-metrics.md)\nfor exact byte, character, duration, and resume semantics.\n\nThe public API also exports `NativeToolBridge`, `startScreencast`, structured\ntarget helpers, `BrowserSafetyError`, the safety policy types, and warm Docker\nsessions. `startPlaywrightContainer()` and `startCamoufoxContainer()` keep their\nserver containers running while each caller receives a separate browser\ninstance. They do not probe a public endpoint by default. Pass\n`probeInternetEgress: true` only when the fixed `https://1.1.1.1:443`\ndiagnostic is acceptable; the returned `internetEgressProbe` discloses the\ndestination and `hasInternetEgress` is `null` when it was not probed. This does\nnot provide operating-system or network isolation.\n\n## Compare browser interfaces\n\nUse the [positioning and local contract proof](docs/positioning-proof.md) to\ndecide whether this package's bounded tools and managed session lifecycle fit\nyour host, and to reproduce those contracts on a loopback-only fixture. It also\nstates when a direct Playwright program is the better fit.\n\nSee the [evidence-backed browser tool comparison](docs/browser-tool-comparison.md)\nfor a reviewed, source-pinned matrix covering Blop Browser, Playwright CLI,\nPlaywright MCP, agent-browser, and Browser Use CLI with Browser Harness. It\ncompares profiles, parallel isolation, existing-browser access, engines,\nembedding, remote execution, recordings, safety controls, and cleanup.\n\nThe document records competitor advantages and tradeoffs instead of treating\nthe matrix as a ranking. Unknown or untested behavior stays explicit, and every\nnontrivial product cell links to primary evidence.\n\nThe [public claims and evidence](docs/public-claims.md) ledger inventories\nrelease-facing copy and maps each retained material promise to direct evidence\nand a stated boundary.\n\n## Configuration reference\n\nThese environment variables configure sessions and browser infrastructure.\nExplicit CLI flags take precedence where both forms exist.\n\n| Variable                                | Default                          | Purpose                                               |\n| --------------------------------------- | -------------------------------- | ----------------------------------------------------- |\n| `BLOP_BROWSER_SESSION`                  | `default`                        | Session name                                          |\n| `BLOP_BROWSER`                          | `chromium`                       | `chromium` or `camoufox`                              |\n| `BLOP_BROWSER_ANTI_BOT`                 | `off`                            | `on` launches Camoufox; `off` keeps Chromium          |\n| `BLOP_BROWSER_HEADLESS`                 | `1`                              | Set to `0` for a visible browser                      |\n| `BLOP_BROWSER_CDP_ENDPOINT`             | Unset                            | Existing Chrome CDP URL; doesn't authorize attachment |\n| `BLOP_BROWSER_PROFILE`                  | `persistent`                     | `persistent` or `disposable` managed profile mode     |\n| `BLOP_BROWSER_TELEMETRY`                | `off`                            | First-party harness telemetry; only `off` is valid    |\n| `BLOP_BROWSER_CONFIG_PATH`              | Platform config directory        | Saved installer choice                                |\n| `BLOP_BROWSER_EXECUTABLE_PATH`          | Auto-detect                      | Chrome or Chromium path                               |\n| `BLOP_BROWSER_CAMOUFOX_EXECUTABLE_PATH` | Auto-detect                      | Camoufox path                                         |\n| `BLOP_BROWSER_IDLE_TIMEOUT_MS`          | `1800000`                        | Daemon idle timeout                                   |\n| `BLOP_BROWSER_READ_ONLY`                | Unset                            | Set to `1` to deny interactions                       |\n| `BLOP_BROWSER_AGENT_ID`                 | Unset                            | Optional identity in bounded action traces            |\n| `BLOP_BROWSER_RUNTIME_DIR`              | OS temporary directory           | Private session state                                 |\n| `BLOP_PLAYWRIGHT_CONTAINER`             | `blop-playwright`                | Warm Playwright server container name                 |\n| `BLOP_PLAYWRIGHT_IMAGE`                 | Playwright-version-derived image | Playwright image override                             |\n| `BLOP_PLAYWRIGHT_NETWORK`               | Unset                            | Shared Docker network                                 |\n| `BLOP_CAMOUFOX_CONTAINER`               | `blop-camoufox`                  | Warm Camoufox server container name                   |\n| `BLOP_CAMOUFOX_IMAGE`                   | Version-derived local image      | Camoufox image override                               |\n| `BLOP_CAMOUFOX_NETWORK`                 | `BLOP_PLAYWRIGHT_NETWORK`        | Camoufox Docker network                               |\n\n## Benchmarks\n\nThe benchmark scaffold separates harness behavior from the agent/model that\ndrives it. No benchmark result is claimed without a reproducible run record.\n\nStart with the [benchmark plan and result schema](benchmarks/README.md). The\n[local session metrics protocol](benchmarks/session-metrics/README.md) measures\nthree paired cold-start and warm-resume workflows against a deterministic\nloopback fixture. Its\n[dated local result](benchmarks/session-metrics/RESULTS.md) publishes all six\ntimed phases and limitations without committing the full report. The\n[Mind2Web live benchmark](benchmarks/mind2web/README.md) contains the normalized\ndataset utility, agent-neutral runner, Blop host adapter, deterministic local\nsmoke test, and historical experiment ledger.\n\n## Contribute\n\nContributions are welcome across browser tools, session infrastructure,\ndocumentation, and benchmark adapters.\n\nRead [CONTRIBUTING.md](CONTRIBUTING.md) for setup, architecture boundaries,\ntests, and pull-request expectations. The [roadmap](ROADMAP.md) lists the near\nterm direction, and the maintainer's\n[candidate good-first-issue backlog](docs/good-first-issues.md) contains scoped\ntasks that can be promoted to GitHub issues after review.\n\n## Project policies\n\nReview the project policies before reporting sensitive problems or taking part\nin the community. Product vulnerabilities use the private security process;\nsupport questions and ordinary bugs are public after sensitive data is removed.\n\n- [Code of Conduct](CODE_OF_CONDUCT.md)\n- [Acceptable-use policy](ACCEPTABLE_USE.md)\n- [Security policy](SECURITY.md)\n- [MIT license](LICENSE)\n\nThe [public launch checklist](docs/launch-checklist.md) records remaining GitHub\nsettings that maintainers must complete manually. The canonical repository is\n`blop-oss/blop-browser`; GitHub redirects its previous `browser-harness` URL.\n","readmeFilename":"README.md"}