4.5 KiB
Agent handshake — Firefox Agent Bridge
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.
Preconditions
- Native host installed:
powershell -NoProfile -File tools/install-native-host.ps1 - Extension loaded in the target Firefox profile (
about:debuggingtemporary add-on, or a signed install) - Firefox running (the host process is started by the extension)
If http://127.0.0.1:17634/health fails, the host is not up — open Firefox and confirm the extension is loaded. If /health works but /v1/ready fails, the stdio pipe is down; reload the extension.
Auth
Token file (created by the installer):
%LOCALAPPDATA%\firefox-agent-bridge\token
Send it on every request except /health:
Authorization: Bearer <token>
Override with env FAB_TOKEN or FAB_URL (default http://127.0.0.1:17634).
Preferred caller
From this repo:
python tools/client.py METHOD [ARGS_JSON]
ARGS_JSON is a JSON array matching the WebExtension function arguments.
Examples:
python tools/client.py meta.methods
python tools/client.py bookmarks.search "[{\"title\":\"10.132.x.x\"}]"
python tools/client.py bookmarks.getChildren "[\"FOLDER_ID\"]"
python tools/client.py bookmarks.create "[{\"parentId\":\"FOLDER_ID\",\"title\":\"NPM\",\"url\":\"http://10.132.99.80:81/\"}]"
python tools/client.py bookmarks.remove "[\"BOOKMARK_ID\"]"
python tools/client.py bookmarks.removeTree "[\"FOLDER_ID\"]"
HTTP equivalent:
POST /v1/call
Content-Type: application/json
{"method": "bookmarks.search", "args": [{"title": "10.132.x.x"}]}
Allowlisted methods (v0.1)
| Method | Args | Notes |
|---|---|---|
meta.ping |
(none) | Bridge alive |
meta.methods |
(none) | This table |
bookmarks.getTree |
(none) | Full tree |
bookmarks.getSubTree |
id |
|
bookmarks.getChildren |
id |
|
bookmarks.get |
id or [id, …] |
|
bookmarks.search |
{title? url? query?} or string |
|
bookmarks.create |
{parentId?, title, url?} |
Omit url to create a folder |
bookmarks.update |
id, {title? url?} |
|
bookmarks.move |
id, {parentId? index?} |
|
bookmarks.remove |
id |
Bookmark or empty folder |
bookmarks.removeTree |
id |
Folder and descendants |
bookmarks.getRecent |
numberOfItems |
Do not invent other browser.* names. Adding an API means editing ALLOWED in extension/background.js and reloading the extension.
REST aliases (same auth):
| HTTP | Maps to |
|---|---|
GET /health |
host process only (no token) |
GET /v1/ready |
meta.ping |
GET /v1/methods |
meta.methods |
GET /v1/bookmarks/tree |
bookmarks.getTree |
GET /v1/bookmarks/{id} |
bookmarks.get |
POST /v1/bookmarks/search |
body is the query object |
POST /v1/bookmarks/create |
body is CreateDetails |
POST /v1/bookmarks/update |
{id, changes} |
POST /v1/bookmarks/move |
{id, destination} |
POST /v1/bookmarks/remove |
{id} |
POST /v1/bookmarks/remove-tree |
{id} |
POST /v1/call |
{method, args} |
Typical folder replace
bookmarks.search{title: "…"}— take the hit without aurl(that is the folder). Fail if zero or many.bookmarks.getChildrenon that id.bookmarks.removeeach bookmark;bookmarks.removeTreeeach child folder.bookmarks.createeach new item withparentIdset.
examples/replace_named_folder.py does exactly that. It is an example, not a sync service.
You cannot modify Firefox's bookmark root (The bookmark root cannot be modified). Operate on a named subfolder (toolbar / menu / a folder the user already created).
Failure modes
| Symptom | Cause | What to do |
|---|---|---|
Connection refused on :17634 |
Firefox closed or extension not loaded | Open Firefox; load/reload the add-on |
| 401 | Missing/wrong bearer | Read the token file |
502 method not allowed |
Typo or API not in ALLOWED |
Use meta.methods |
| 502 timeout | Extension died mid-call | Reload the add-on |
| Temporary add-on gone after restart | Unsigned on Firefox Release | Load again, or sign via AMO unlisted |
| Native host not found | Installer not run | tools/install-native-host.ps1 |
What this project is not
- Not a bidirectional sync implementation
- Not a general Firefox remote-control surface (no tabs, history, cookies, native file access)
- Not a reason to keep editing
places.sqliteon a live profile