Open an installed app
Select a Tool pack as usual, then runfiredrill serve. The command starts its
backend and any declared app on local ports. Tools → Open app in the inspector
opens that Tool’s app. The terminal also prints each app link. No account, Docker,
extra frontend server, or drill definition is needed.
A packaged app can provide a familiar interface for any stateful Tool while
remaining bounded by that package’s declared operations and fidelity. It must not
imply behavior the Tool does not implement. Document those limits in the package
README so users can judge whether it fits their drill.
Backend-only packs keep working without an app. An app does not replace HTTP,
MCP, CLI, or test-side function bindings.
Add your own UI
Keep the Tool’s declaration and behavior. Add an optionalui field at the top
level of its .tool.json or .tool.yaml declaration:
schemaVersion,
module, and complete manifest. root is relative to the declaration, inside the source
root or installed package. entry defaults to index.html. Use plain HTML,
CSS, and JavaScript, or your preferred frontend’s static build output. Server-side
rendering and a separate package-owned Node server are not part of this contract.
{ idempotencyKey: crypto.randomUUID() } as the
third argument. Reuse that key when retrying the same uncertain action; create
a new key for a new action. The helper does not silently retry mutations.
getContext() is read-only. Its revision lets an app refresh after changes
without repeatedly loading records. Do not overwrite a user’s unsaved form when
refreshing. Use version checks in Tool operations to reject stale edits.
Shared state, separate authority
Each app gets its own loopback origin and a credential scoped to one Tool and the selected actor. Opening an app cannot grant extra permissions, change actors, read raw SQLite, reset the world, or control the inspector. A backend-only Tool can still participate in the same world. Cross-Tool consequences belong in declared behavior and event contracts, not privileged browser calls. App links contain short-lived local credentials in their URL fragment. The helper removes the fragment before making requests and keeps the credential in that tab’s session storage for reloads. Do not commit, publish, or share the original links. Closing the environment closes its app listeners. Full reset restores the world’s baseline while keeping active connections usable; it does not delete saved reports or change source files. The compiler copies exact app assets into the immutable build and verifies their hashes when loading it. Editing source does not silently change a running app; restartserve to compile the new version. tool inspect includes the UI asset
manifest and source closure. Community contribution bundles include those exact
assets and retain source/credential checks.
Supported assets are bounded HTML, CSS, JavaScript, JSON, images, and fonts. The
limits are 256 files, 4 MiB per file, and 16 MiB per app. Hidden files, symlinks,
credential-like paths, dependency folders, path escapes, and the reserved
_firedrill/ directory are rejected. Bundle dependencies and fonts locally;
inline scripts/styles, external resources, frames, workers, and remote requests
are blocked by the serving policy. Tool code is still trusted local code—these
browser restrictions are not an OS sandbox for package behavior.
Browser agents and testing
You can open the app yourself or drive it with browser automation. Browser interaction produces ordinary Tool operations, state changes, and evidence. DuringrunDrills, the target callback receives binding.apps, an array of
{ packageId, title, url } for that interaction’s Tool apps. Command targets
receive the same array as JSON in FIREDRILL_TOOL_APPS. Use the selected URL in
your test-owned browser launch/configuration; do not hardcode a port or edit the
production agent. Each attempt gets fresh credentials and closes its listeners
when the interaction ends, including failure or timeout. Standalone SDK callers
get the same apps array from world.listen() and own its lifetime.
Use the browser testing package or
your own Playwright harness. Optional screenshots, recordings, and logs use the
normal capture API. A successful page click alone is not proof that
your agent passed: assert the intended state and behavior in a drill.
Inline target results and diagnostics redact issued app credentials. Caller-added
attachments are still verbatim data: do not attach files containing credentials,
and use the capture/redaction controls when recording your own browser or logs.