Rename the add-on Bookmarks API and drop CLI copy from the product UI.
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
# Agent handshake — Firefox Agent Bridge
|
||||
# Agent handshake — Bookmarks API for Scripting and AI
|
||||
|
||||
Use this when working **in this repo**. The shipped product is the add-on under `extension/` only. Do not treat `tools/` as part of the listing.
|
||||
|
||||
Use this when a script or coding agent needs to **create, update, move, or delete Firefox bookmarks while Firefox is open**. Do not edit `places.sqlite` if this bridge is reachable.
|
||||
|
||||
@@ -15,7 +17,7 @@ If `http://127.0.0.1:17634/health` fails, the host is not up. If `/health` works
|
||||
|
||||
This is a normal API token, not an SSH key.
|
||||
|
||||
1. In Firefox, open the Agent Bridge toolbar icon → **Manage clients**.
|
||||
1. In Firefox, open the Bookmarks API toolbar icon → **Manage clients**.
|
||||
2. Name the client (e.g. `cursor-agent`) and click **Generate secret**.
|
||||
3. Copy the `fab_…` value **once**. Store it however you already store secrets: env var, Vaultwarden, `.env`, CI secret, Cursor env.
|
||||
4. Give tooling only that string:
|
||||
|
||||
@@ -1,53 +1,24 @@
|
||||
# Firefox Agent Bridge
|
||||
# Bookmarks API for Scripting and AI
|
||||
|
||||
A small Firefox add-on that exposes an **allowlisted** WebExtension API to local scripts and agents — after you issue them a secret from inside Firefox.
|
||||
A Firefox add-on that lets **local** scripts and agents call an allowlisted `browser.bookmarks` API — after you issue them a secret from inside the browser.
|
||||
|
||||
This is **not** a bookmark sync engine. Firefox already has `browser.bookmarks`. The add-on is a bridge: while Firefox is open, a script on the same machine can call those functions over `http://127.0.0.1:17634` with a Bearer token.
|
||||
The published product is the add-on in `extension/`. It does not ship helper scripts. Callers use ordinary HTTP and a Bearer token, stored however they already keep secrets.
|
||||
|
||||
Agents: start at [AGENTS.md](AGENTS.md).
|
||||
|
||||
## Why this exists
|
||||
|
||||
Firefox will not let an outside process talk to Places. Editing `places.sqlite` while the browser is running loses deletes. The supported path is `browser.bookmarks` inside an extension, plus [native messaging](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Native_messaging) so a localhost HTTP host can reach that extension.
|
||||
This is not a bookmark sync engine, and it is not a Mozilla product. Mozilla’s add-on naming rule is “Name for Firefox,” never “Firefox Name”; this listing uses neither form in the title.
|
||||
|
||||
## Setup
|
||||
|
||||
1. Register the native host (once):
|
||||
1. Register the native host once (`tools/install-native-host.ps1` on this workstation).
|
||||
2. Load the add-on (temporary via `about:debugging`, or a signed `.xpi` — [docs/signing.md](docs/signing.md)).
|
||||
3. Toolbar icon → **Manage clients** → generate a secret → store it with your secrets.
|
||||
|
||||
```powershell
|
||||
powershell -NoProfile -File tools\install-native-host.ps1
|
||||
```
|
||||
|
||||
2. Load the add-on (`about:debugging` temporary, or a signed `.xpi` — [docs/signing.md](docs/signing.md)).
|
||||
|
||||
3. Click the toolbar icon → **Manage clients** → name a client → **Generate secret**. Copy the `fab_…` token into whatever secret store you already use.
|
||||
|
||||
4. Leave Firefox open. `GET http://127.0.0.1:17634/health` should return JSON.
|
||||
|
||||
## Call it
|
||||
|
||||
```powershell
|
||||
$env:FAB_TOKEN = "fab_…" # the value from the Manage clients modal
|
||||
python tools/client.py meta.methods
|
||||
python tools/client.py bookmarks.search '[{"title":"10.132.x.x"}]'
|
||||
```
|
||||
|
||||
`curl` works the same: `Authorization: Bearer fab_…`.
|
||||
While Firefox is open, `http://127.0.0.1:17634/health` answers if the host is up. Authenticated calls use `Authorization: Bearer <secret>` on `/v1/call`. Method list: the repo [AGENTS.md](AGENTS.md) (for people working on this codebase, not for the AMO listing).
|
||||
|
||||
## Security
|
||||
|
||||
- Binds **127.0.0.1** only. Browser `Origin` headers are rejected.
|
||||
- Each caller is an issued token. The add-on stores a hash, not the secret.
|
||||
- Only `bookmarks.*` (plus `meta.*`) in `extension/background.js`. No history, cookies, tabs, or `onMessageExternal`.
|
||||
|
||||
## Pieces
|
||||
|
||||
| Piece | Role |
|
||||
|-------|------|
|
||||
| `extension/` | Add-on, popup, Manage clients page |
|
||||
| `host/` | Native host: stdio to Firefox, HTTP to scripts |
|
||||
| `tools/client.py` | Bearer caller (`FAB_TOKEN`) |
|
||||
| `examples/replace_named_folder.py` | Sample folder replace |
|
||||
- Only `bookmarks.*` (plus `meta.*`). No history, cookies, tabs, or `onMessageExternal`.
|
||||
|
||||
## License
|
||||
|
||||
|
||||
+1
-1
@@ -42,4 +42,4 @@ Bump `version`, sign again on the same channel and id. For unlisted self-distrib
|
||||
|
||||
## 5. Listed (later)
|
||||
|
||||
`web-ext sign --channel=listed` plus an AMO metadata JSON (name, summary, license MIT). Expect listing copy that says: local scripts only, loopback HTTP, bearer token, bookmarks allowlist. Do not claim it is a general Firefox remote-control tool.
|
||||
`web-ext sign --channel=listed` plus an AMO metadata JSON (name **Bookmarks API for Scripting and AI**, license MIT). Listing copy: local scripts only, loopback HTTP, bearer token, bookmarks allowlist. Do not title it “Firefox …”. Mozilla only allows “Name for Firefox”; this add-on uses neither form.
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
{
|
||||
"manifest_version": 3,
|
||||
"name": "Firefox Agent Bridge",
|
||||
"version": "0.2.0",
|
||||
"description": "Let local scripts and agents call an allowlisted WebExtension API after you issue them a secret.",
|
||||
"name": "Bookmarks API for Scripting and AI",
|
||||
"short_name": "Bookmarks API",
|
||||
"version": "0.3.0",
|
||||
"description": "Issue a secret, then let local scripts and agents call an allowlisted bookmarks API.",
|
||||
"browser_specific_settings": {
|
||||
"gecko": {
|
||||
"id": "firefox-agent-bridge@easygoingaming.com",
|
||||
@@ -14,7 +15,7 @@
|
||||
"scripts": ["background.js"]
|
||||
},
|
||||
"action": {
|
||||
"default_title": "Firefox Agent Bridge",
|
||||
"default_title": "Bookmarks API",
|
||||
"default_popup": "popup.html"
|
||||
},
|
||||
"options_ui": {
|
||||
|
||||
@@ -2,18 +2,18 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Firefox Agent Bridge</title>
|
||||
<title>Bookmarks API</title>
|
||||
<link rel="stylesheet" href="ui.css">
|
||||
</head>
|
||||
<body class="page">
|
||||
<header>
|
||||
<h1>Firefox Agent Bridge</h1>
|
||||
<p class="muted">Issue a secret to each script or agent. The add-on keeps only a hash. Put the secret in an env var, vault, or <code>.env</code> — whatever you already use.</p>
|
||||
<h1>Bookmarks API for Scripting and AI</h1>
|
||||
<p class="muted">Issue a secret to each client. Store it with your secrets. This add-on keeps only a hash.</p>
|
||||
<p id="status" class="muted"></p>
|
||||
</header>
|
||||
|
||||
<section class="row">
|
||||
<input id="name" type="text" maxlength="64" placeholder="Client name, e.g. cursor-agent" autocomplete="off">
|
||||
<input id="name" type="text" maxlength="64" placeholder="Client name" autocomplete="off">
|
||||
<button id="create" type="button">Generate secret</button>
|
||||
</section>
|
||||
<p id="error" class="error" hidden></p>
|
||||
@@ -34,10 +34,9 @@
|
||||
|
||||
<dialog id="secret-modal">
|
||||
<h2>Copy this secret now</h2>
|
||||
<p class="muted">It will not be shown again. Store it the same way you store any other API token.</p>
|
||||
<p class="muted">It will not be shown again. Store it with your secrets.</p>
|
||||
<label class="sr">Secret</label>
|
||||
<textarea id="secret" readonly rows="3"></textarea>
|
||||
<p class="hint">Example: <code>set FAB_TOKEN=<secret></code> then <code>python tools/client.py meta.methods</code></p>
|
||||
<div class="row">
|
||||
<button id="copy" type="button">Copy</button>
|
||||
<button id="close" type="button">I saved it</button>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<link rel="stylesheet" href="ui.css">
|
||||
</head>
|
||||
<body class="popup">
|
||||
<h1>Agent Bridge</h1>
|
||||
<h1>Bookmarks API</h1>
|
||||
<p id="status" class="muted">Checking host…</p>
|
||||
<button id="manage" type="button">Manage clients</button>
|
||||
<script src="popup.js"></script>
|
||||
|
||||
@@ -23,7 +23,7 @@ if (Test-Path $TokenPath) {
|
||||
|
||||
$manifest = @{
|
||||
name = $HostName
|
||||
description = "Firefox Agent Bridge native host"
|
||||
description = "Bookmarks API native host"
|
||||
path = $CmdPath
|
||||
type = "stdio"
|
||||
allowed_extensions = @($ExtensionId)
|
||||
@@ -38,4 +38,4 @@ Write-Host "registered $regPath"
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Load the add-on, then use the toolbar icon → Manage clients to generate a secret."
|
||||
Write-Host "Put that fab_… token in FAB_TOKEN for scripts. Do not store it under $StateDir."
|
||||
Write-Host "Store that secret with your other secrets. Do not keep it under $StateDir."
|
||||
|
||||
Reference in New Issue
Block a user