Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message
Agents
particle-academy/prism-browser
claude-code
cursor
browser-policy
error-codes
ssrf
playwright
sidecar
dns-rebinding
breaking-changes

Guarded open-web automation for Prism agents. Read the shared ecosystem guide in prism-parity/docs/AGENTS.md first.

Install
php artisan boost:add-skill particle-academy/prism-browser

Save this content to: AGENTS.md

# AGENTS.md — particle-academy/prism-browser

Guarded open-web automation for Prism agents. Read the shared ecosystem guide
in `prism-parity/docs/AGENTS.md` first.

## The guard is the product

The engine is replaceable plumbing. The package must refuse before reaching an
engine when navigation, observation, or action falls outside declared policy.
Never add arbitrary JavaScript evaluation, model-supplied selectors, ambient
credentials, unbounded page output, implicit redirects, or silent fallback.

Human+ participation is not a browser mode and belongs in `prism-human-plus`.

## Refusals are codes, and one of them just changed — BREAKING

`BrowserRefused` carries a stable code read with `code()`. **Never branch on the
message**, here or in a consumer; prism-parity
[decision 0004](https://github.com/Particle-Academy/prism-parity/blob/main/docs/decisions/0004-error-codes.md)
is why, and the sentences are deliberately worded differently in each of the
three languages.

Two breaking moves closed gap G-21, and neither has a deprecation shim:

- `$refused->reason` → **`$refused->code()`**. A method, not a property:
  `Exception::$code` is an untyped int and a subclass may not retype it, which
  is the same reason `Prism\Harness\Contracts\HasErrorCode` is a method.
- `private_network_refused` → **`private_address_refused`**, matching both
  ports. The check is per-address; an allow-list entry naming one does not
  widen it.

An alias was rejected on purpose: it would have kept `$e->reason` readable while
its value moved, turning a comparison against the old code from true to silently
false on the one branch where a wrong answer misreads an SSRF refusal as an
unknown failure. Removing the property makes that code raise instead.

**There are three places that can emit a policy code, not one.** `BrowserPolicy`
is the in-process gate; `sidecar/security.mjs` checks the literal AND re-checks
after DNS; and `PlaywrightSidecarEngine` passes whatever the sidecar named to
the caller unchanged. Change a code in one and the package disagrees with
itself, on the path that actually resists rebinding. `tests/Unit/UrlPolicyCorpusTest.php`
asserts the retired name appears in neither the corpus nor the sidecar.

## Gates

```sh
composer test && composer types && composer format
```

AGENTS.md — particle-academy/prism-browser

Guarded open-web automation for Prism agents. Read the shared ecosystem guide in prism-parity/docs/AGENTS.md first.

The guard is the product

The engine is replaceable plumbing. The package must refuse before reaching an engine when navigation, observation, or action falls outside declared policy. Never add arbitrary JavaScript evaluation, model-supplied selectors, ambient credentials, unbounded page output, implicit redirects, or silent fallback.

Human+ participation is not a browser mode and belongs in prism-human-plus.

Refusals are codes, and one of them just changed — BREAKING

BrowserRefused carries a stable code read with code(). Never branch on the message, here or in a consumer; prism-parity decision 0004 is why, and the sentences are deliberately worded differently in each of the three languages.

Two breaking moves closed gap G-21, and neither has a deprecation shim:

  • $refused->reason → $refused->code(). A method, not a property: Exception::$code is an untyped int and a subclass may not retype it, which is the same reason Prism\Harness\Contracts\HasErrorCode is a method.
  • private_network_refused → private_address_refused, matching both ports. The check is per-address; an allow-list entry naming one does not widen it.

An alias was rejected on purpose: it would have kept $e->reason readable while its value moved, turning a comparison against the old code from true to silently false on the one branch where a wrong answer misreads an SSRF refusal as an unknown failure. Removing the property makes that code raise instead.

There are three places that can emit a policy code, not one. BrowserPolicy is the in-process gate; sidecar/security.mjs checks the literal AND re-checks after DNS; and PlaywrightSidecarEngine passes whatever the sidecar named to the caller unchanged. Change a code in one and the package disagrees with itself, on the path that actually resists rebinding. tests/Unit/UrlPolicyCorpusTest.php asserts the retired name appears in neither the corpus nor the sidecar.

Gates

composer test && composer types && composer format
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core