# BridgeAble Deployment & Testing Guide

This guide walks through running BridgeAble locally, deploying it, and testing both (a) the
built-in demo agent (works in any modern browser today) and (b) real, browser-native WebMCP tool
discovery (Chrome only, behind a flag or origin trial, as of 2026).

---

## Table of contents

1. [Prerequisites](#prerequisites)
2. [Local setup](#local-setup)
3. [Configure the LLM](#configure-the-llm)
4. [Run it](#run-it)
5. [Test the built-in accessible agent](#test-the-built-in-accessible-agent)
6. [Test real WebMCP tool discovery in Chrome](#test-real-webmcp-tool-discovery-in-chrome)
7. [Accessibility testing checklist](#accessibility-testing-checklist)
8. [Production deployment](#production-deployment)
9. [Retrofitting BridgeAble onto your own site](#retrofitting-bridgeable-onto-your-own-site)
10. [Troubleshooting](#troubleshooting)

---

## Prerequisites

| Requirement | Minimum version | Notes |
|---|---|---|
| PHP | 8.1+ | With the `curl` and `json` extensions (both bundled by default) |
| A browser | Any recent Chrome, Edge, Firefox, or Safari | Chat/voice panel works everywhere; native WebMCP registration currently requires Chrome 140+ |
| An LLM API key | — | Any OpenAI-compatible Chat Completions endpoint that supports `tools`/function calling (OpenAI `gpt-4o`/`gpt-4o-mini`, Groq, OpenRouter, Azure OpenAI, etc.) |

No database, no build step, no Node.js required — this is a flat, vanilla PHP + JS app.

---

## Local setup

```bash
cd bridgeable
cp .env.example .env
cp config.example.php config.php
```

Edit `.env`:

```
LLM_API_URL=https://api.openai.com/v1/chat/completions
LLM_API_KEY=sk-...your key...
LLM_MODEL=gpt-4o-mini
APP_URL=http://localhost:8080
```

If you use a non-OpenAI provider, just point `LLM_API_URL` at its OpenAI-compatible
`/chat/completions` endpoint and set the right `LLM_MODEL` — as long as it supports the `tools`
parameter in the request body, no code changes are needed.

---

## Configure the LLM

`llm.php` sends a standard OpenAI-style payload:

```json
{
  "model": "gpt-4o-mini",
  "messages": [...],
  "tools": [{ "type": "function", "function": { "name": "...", "description": "...", "parameters": {...} } }],
  "tool_choice": "auto"
}
```

If `LLM_API_KEY` is left blank, the app still runs — the demo host page, WebMCP tool registration,
and the manual "Undo" / "Read back my info" buttons keep working, but the chat/voice input will
respond with a friendly message asking you to configure a key instead of silently failing.

---

## Run it

```bash
php -S localhost:8080
```

Open:
- `http://localhost:8080/` — landing page
- `http://localhost:8080/portal.php` — the demo host site with BridgeAble embedded

### Apache / Nginx

Same pattern as any flat PHP app — point the document root at this folder and make sure `.env` /
`config.php` are not web-accessible (already covered by `.gitignore`; also block them at the web
server level in production, see [Production deployment](#production-deployment)).

---

## Test the built-in accessible agent

This works today, in any browser, with no special flags.

1. Open `http://localhost:8080/portal.php`. Note how messy/inaccessible the raw form is on purpose:
   no visible labels, placeholder-only hints, tiny buttons, no progress indicator.
2. Click the round assistant button in the bottom-right corner (🤝).
3. Type (or click the 🎤 mic button and speak):
   > "I want to apply for housing assistance. My name is Maria Gomez, I have two dependents, and my income is $2,400 a month."
4. Watch the underlying form fields light up and populate live as BridgeAble calls `fill_field` and
   `go_to_step` — this is the "live sync" trust mechanism: nothing happens invisibly.
5. Try a correction: "Actually my income is $2,600." — BridgeAble should call `fill_field` again
   rather than starting over.
6. Ask it to explain something: "What does housing status mean?" → calls `explain_field`.
7. Ask it to read a field back: "Read my income back to me." → calls `read_field_aloud` and speaks
   via the browser's text-to-speech (enable "Speak assistant replies aloud" in the panel to also
   have every chat reply spoken).
8. Say "I've attached my ID and proof of income." → BridgeAble calls `upload_document` for each,
   marking the corresponding status as uploaded. A document can also be uploaded manually at any
   time on the raw page itself, on Step 3 ("Documents") — each row has a real (deliberately tiny,
   unlabeled) file picker; choosing a file there updates the same status the assistant reads.
9. Say "I'm done, submit it." → BridgeAble calls `request_submit`, which opens the **confirmation
   card** with a plain-language summary. Nothing is submitted yet.
10. Tap **"✅ Confirm & Submit"** yourself — only this direct human tap actually submits the form
    (you'll see the portal's own green "submitted successfully" banner). Tapping **"✏ Let me fix
    something"** instead just closes the card so you can keep editing.
11. Use the **"↩ Undo last change"** quick-action button (or say "undo that") to revert the most
    recent field edit or document upload.

Open the browser DevTools console — you should see log lines like
`[BridgeAble] Registered WebMCP tool: fill_field` confirming the tools were registered via
`document.modelContext` if your browser supports it, or a note explaining that WebMCP itself isn't
available but the built-in panel still works.

---

## Test real WebMCP tool discovery in Chrome

WebMCP (`document.modelContext`) is a proposed, still-experimental web standard. As of writing it
ships in Chrome behind a flag for local testing, or via an [origin trial](https://developer.chrome.com/origintrials/#/register_trial/4163014905550602241)
for a real deployment. Reference docs: [github.com/webmachinelearning/webmcp](https://github.com/webmachinelearning/webmcp)
and [developer.chrome.com/docs/ai/webmcp](https://developer.chrome.com/docs/ai/webmcp).

### Option A — Local Chrome flag (fastest)

1. Open Chrome and go to `chrome://flags/#enable-webmcp-testing`.
2. Set it to **Enabled**, then relaunch Chrome.
3. Load `http://localhost:8080/portal.php`. In DevTools console, check:
   ```js
   'modelContext' in document // should now be true
   document.modelContext
   ```
4. Install the **[Model Context Tool Inspector extension](https://chromewebstore.google.com/detail/model-context-tool-inspec/gbpdfapgefenggkahomfgkhfeh lcenpd)**
   from the Chrome Web Store.
5. Open the extension on the `portal.php` tab. You should see all nine BridgeAble tools listed
   (`get_application_state`, `fill_field`, `go_to_step`, `upload_document`, `explain_field`,
   `read_field_aloud`, `review_summary`, `request_submit`, `undo_last_change`) with their JSON
   Schemas.
6. Use the extension's built-in chat (backed by Gemini) to say something like "fill in the first
   name field with Maria" and confirm it calls `fill_field` correctly and the page updates. You can
   also manually invoke a tool from the extension UI and inspect the returned structured result.

This validates that BridgeAble's tools are spec-compliant and independently discoverable/callable
by *any* WebMCP-aware agent, not just BridgeAble's own bundled chat panel.

### Option B — Origin trial (for a real deployed domain)

1. Register for the WebMCP origin trial at the token registration page linked from
   [developer.chrome.com/docs/ai/webmcp](https://developer.chrome.com/docs/ai/webmcp) (requires a
   real, deployed origin — not `localhost`).
2. Add the issued token to `portal.php`'s `<head>` by uncommenting:
   ```html
   <meta http-equiv="origin-trial" content="YOUR_ORIGIN_TRIAL_TOKEN">
   ```
3. Deploy and reload — users on stock Chrome (no flag needed) within the trial period will have
   `document.modelContext` available.

### Notes on WebMCP security requirements

- WebMCP requires an **origin-isolated document**. If the page sets `document.domain` (or serves an
  `Origin-Agent-Cluster: ?0` header), the API is disabled. `portal.php` does neither, so it's fine
  out of the box.
- Tool registration is gated by the `tools` Permissions Policy (defaults to `self`). If you embed
  `portal.php` in a cross-origin `<iframe>` elsewhere, add `allow="tools"` to that iframe.

---

## Accessibility testing checklist

BridgeAble's panel is designed to be usable without a mouse and without sight:

- [ ] **Keyboard only:** Tab through the launcher button, panel controls, quick actions, input,
      mic, send, and confirmation buttons — every control should be reachable and operable with
      Tab + Enter/Space alone (no drag, no hover-only affordances).
- [ ] **Screen reader:** Turn on VoiceOver/NVDA/Narrator. The chat log is an
      `role="log" aria-live="polite"` region, so new assistant messages are announced automatically.
- [ ] **Voice-only:** Try completing the entire application using only the 🎤 mic button and your
      voice, including correcting a value and confirming submission.
- [ ] **Low vision:** Zoom the browser to 200%; panel text uses large (≥15px) font sizes and high
      contrast (light text on dark navy) independent of however messy the underlying host page is.
- [ ] **Switch/single-button style input:** The two always-visible quick-action buttons ("Undo last
      change", "Read back my info") plus the confirmation card's two big buttons are all large
      (44px+) fixed-position targets reachable purely via sequential Tab focus, approximating
      simplified switch-scanning input.

---

## Production deployment

### Security checklist

- [ ] Set `APP_ENV=production` in `.env`.
- [ ] Confirm `.env` and `config.php` are not publicly served — the `.gitignore` keeps them out of
      version control; also add web-server rules blocking dotfiles, e.g. for Apache:
      ```apache
      <FilesMatch "^\.env$|^config\.php$">
          Require all denied
      </FilesMatch>
      ```
- [ ] Serve everything over HTTPS (also a prerequisite for the WebMCP origin trial).
- [ ] Keep the LLM API key server-side only — it never reaches the browser; `agent_api.php` is the
      only thing that talks to the LLM.
- [ ] Rate-limit `agent_api.php` if deploying publicly, to control LLM spend.

### Hosting

- **Shared PHP hosting:** works out of the box — upload the files, create `.env`/`config.php` from
  the examples, done.
- **VPS (Apache/Nginx + PHP-FPM):** standard vhost pointing at this folder.
- **Docker:** not required; no framework or DB dependency, but trivially containerizable with any
  `php:8.1-apache`-style base image if you prefer.

---

## Retrofitting BridgeAble onto your own site

The whole point of BridgeAble is that it's a retrofit, not a rewrite. To add it to an existing page:

1. Add a config object describing your page (see `portal.php` for the full example):
   ```html
   <script>
     window.BridgeableConfig = {
       appName: 'Your App Name',
       steps: [{ id: 1, name: 'Step One' }, /* ... */],
       gotoStep: function (n) { /* however your app already navigates steps */ },
       fields: {
         some_field: { selector: '#your-input-id', label: 'Human-readable label', step: 1, type: 'text' }
       },
       documents: { /* optional, if you have file/document upload steps */ },
       reviewStep: 4,
       submitButtonSelector: '#your-submit-button',
       submittedBannerSelector: '#your-success-banner'
     };
   </script>
   <script src="/path/to/assets/bridgeable-widget.js"></script>
   ```
2. That's it — no other markup or JS changes required. BridgeAble reads your existing DOM through
   the selectors you provided and drives it the same way a human would (setting `.value`, dispatching
   `input`/`change` events, clicking your existing submit button), so your page's own validation and
   event handlers keep working unmodified.

---

## Troubleshooting

| Issue | Solution |
|---|---|
| "Missing .env file" | Copy `.env.example` to `.env` (and `config.example.php` to `config.php`). |
| Chat says BridgeAble isn't fully configured | Set `LLM_API_KEY` in `.env`. |
| LLM API errors in chat | Check `LLM_API_URL` / `LLM_MODEL` are correct for your provider, and that it supports `tools`/function calling. |
| `document.modelContext` is undefined | Expected outside Chrome, or in Chrome without the flag/origin trial enabled — the built-in chat panel works regardless; see [Test real WebMCP tool discovery](#test-real-webmcp-tool-discovery-in-chrome). |
| Voice input button says unsupported | `SpeechRecognition` isn't available in your browser; use Chrome or Edge, or type instead. |
| Fields don't visibly update | Check that `window.BridgeableConfig.fields[...].selector` matches a real element on the page, and that your site doesn't overwrite `.value` on an interval. |
| `LLM request failed: SSL certificate ... unable to get local issuer certificate` (common on Windows PHP) | Your PHP install has no CA bundle configured for cURL. Download [cacert.pem](https://curl.se/docs/caextract.html) and add `curl.cainfo="C:\path\to\cacert.pem"` (and `openssl.cafile=...`) to your `php.ini`, then restart the server. |
