488 lines
22 KiB
Markdown
488 lines
22 KiB
Markdown
# sovereign_browser
|
|
|
|
A Linux x86 web browser built in C99 on WebKitGTK, designed around
|
|
**sovereign identity** instead of the traditional web's permissioned
|
|
infrastructure.
|
|
|
|
The thesis: the browser's security model (DNS/domains, TLS/CAs, same-origin
|
|
policy, CORS, cookie sandboxing) is what forces you to rely on permissioned
|
|
domains, certificate authorities, and centralized account systems. By
|
|
deprecating that model and replacing it with **Nostr identity** and **FIPS
|
|
mesh transport**, you get a browser that's more capable, not less safe —
|
|
because trust moves to the layer where it belongs: your keys.
|
|
|
|
> "Not your keys, not your browser." Walk up to a computer with your Nostr
|
|
> identity (via [n_signer](https://github.com/laantungir/n_signer)) and the
|
|
> browser is yours — your identity, your relays, your mesh.
|
|
|
|
## Goals
|
|
|
|
1. **A real browser.** Loads any normal HTTP/HTTPS page via WebKitGTK.
|
|
2. **FIPS addresses are first-class.** `http://<npub>.fips/` and `fips://`
|
|
resolve over the [FIPS](https://github.com/jmcorgan/fips) mesh, not DNS/IP.
|
|
Reach any FIPS node by its Nostr npub, no domain, no public IP, no TLS cert.
|
|
3. **Built-in Nostr signing.** The browser injects `window.nostr` (the
|
|
[nos2x](https://github.com/fiatjaf/nos2x) surface) into every page, backed
|
|
by [n_signer](https://github.com/laantungir/n_signer) — a foreground,
|
|
RAM-only, human-attended signing program. The browser never holds your
|
|
private key; every signature is approved at the signer's terminal.
|
|
4. **Deprecated web security, deliberately.** Same-origin policy, CORS, and
|
|
certificate enforcement are stripped so pages (and the agent runtime to
|
|
come) can freely call any endpoint — including FIPS mesh services — without
|
|
the workarounds traditional browsers force on automators. Security moves
|
|
up to the **Qube level** (isolation per VM), so the browser doesn't need
|
|
the traditional in-browser security model.
|
|
5. **Local file browsing.** Open and operate multipage websites directly from
|
|
`file://` with no web server — cross-origin access between local files,
|
|
`fetch()`/XHR, iframes, storage, media playback, all work. See
|
|
[Local file browsing](#local-file-browsing) below.
|
|
|
|
## Nostr interaction policy
|
|
|
|
sovereign_browser interacts with Nostr via **discrete events only** — no
|
|
continuous WebSocket subscriptions. The browser fetches events on demand
|
|
(via `relay_fetch.c`) and publishes events on demand (via `settings_sync.c`,
|
|
`agent_conversations.c`, `agent_skills.c`). There is no persistent
|
|
subscription that receives live updates.
|
|
|
|
This is a deliberate architectural choice:
|
|
|
|
- **Simplicity** — No subscription lifecycle management, no reconnection
|
|
logic, no event deduplication across reconnects.
|
|
- **Predictability** — The user controls when data is fetched or published.
|
|
No background traffic, no surprise events arriving.
|
|
- **Resource efficiency** — No open WebSocket connections consuming memory
|
|
and bandwidth while idle.
|
|
|
|
**Trade-off:** The browser does not receive live updates. If a conversation
|
|
or skill is created in another app (e.g., the client web app), it won't
|
|
appear in sovereign_browser until the user explicitly refreshes. UIs that
|
|
need fresh data provide **Refresh buttons** that trigger a one-shot fetch.
|
|
|
|
### What this means for the chat page
|
|
|
|
The `sovereign://agents/chat` page differs from `~/lt/client/www/ai.html`
|
|
in this respect:
|
|
|
|
- **ai.html** uses NDK with persistent subscriptions — conversations and
|
|
skills appear live as they're published to relays.
|
|
- **sovereign_browser** fetches conversations and skills on demand — the
|
|
user clicks a Refresh button to pull new data from relays.
|
|
|
|
Conversations and skills are still stored as the same Nostr event kinds
|
|
(30078 for conversations, 31123 for skills) with the same tags, so they're
|
|
**compatible** across projects — just not live-synced.
|
|
|
|
## Current status
|
|
|
|
Working browser with a broad feature set:
|
|
|
|
- **Multi-tab browsing** with session restore, tab drag/reorder, context menus
|
|
- **Nostr login** (GTK dialog or CLI flags) with multiple methods: generate,
|
|
local (nsec), seed (BIP-39), readonly (npub), NIP-46, n_signer hardware
|
|
- **`window.nostr` injection** (NIP-07) into every page
|
|
- **Agent MCP server** — 100 tools for browser automation via Streamable HTTP
|
|
at `http://localhost:17777/mcp`
|
|
- **Local file browsing** — open and operate multipage websites directly from
|
|
`file://` with no web server (see below)
|
|
- **Bookmarks, history, search** — built-in bookmark manager, browsing history,
|
|
and search engine integration
|
|
- **Keyboard shortcuts** — standard browser shortcuts (Ctrl+T, Ctrl+W, Ctrl+L,
|
|
Ctrl+Tab, etc.)
|
|
- **Per-user profiles** — separate identities and settings per profile
|
|
- **Embedded web content** — `sovereign://` pages for settings, bookmarks,
|
|
profile, and agent chat/config
|
|
|
|
See [`docs/webkit-poc-findings.md`](docs/webkit-poc-findings.md) for the
|
|
friction report from the POC phase.
|
|
|
|
## Install
|
|
|
|
One-command install on Debian 13 (trixie) or similar (x86_64, WebKitGTK 4.1):
|
|
|
|
```bash
|
|
curl -fsSL https://git.laantungir.net/laantungir/sovereign_browser/raw/branch/master/install.sh | bash
|
|
```
|
|
|
|
This downloads and runs [`install.sh`](install.sh), which:
|
|
|
|
1. Installs runtime dependencies via `apt` (WebKitGTK 4.1, libsoup, curl, etc.)
|
|
2. Installs **Tor** via `apt` (used for `.onion` routing)
|
|
3. Builds and installs **FIPS** from source with `CAP_NET_ADMIN` (used for `.fips` mesh routing)
|
|
4. Downloads the latest prebuilt `sovereign_browser` binary from the [Gitea releases](https://git.laantungir.net/laantungir/sovereign_browser/releases) (falls back to a source build if no binary is available)
|
|
5. Installs a `sovereign-browser` wrapper command to `/usr/local/bin`
|
|
|
|
After install, start the browser with:
|
|
|
|
```bash
|
|
sovereign-browser start --login-method generate
|
|
```
|
|
|
|
### Install options
|
|
|
|
```bash
|
|
# Non-root install to a user-writable prefix
|
|
curl -fsSL <url> | INSTALL_PREFIX=$HOME/.local bash -s -- --yes
|
|
|
|
# Force a source build instead of downloading the prebuilt binary
|
|
curl -fsSL <url> | bash -s -- --build-from-source
|
|
|
|
# Review the script before running it
|
|
curl -fsSL <url> -o install.sh
|
|
less install.sh
|
|
bash install.sh
|
|
```
|
|
|
|
Run `bash install.sh --help` for the full option list.
|
|
|
|
### What the install requires
|
|
|
|
| Requirement | Why |
|
|
|---|---|
|
|
| Debian 13+ / Ubuntu 24.04+ (WebKitGTK 4.1) | The browser is dynamically linked against `libwebkit2gtk-4.1` |
|
|
| x86_64 | Prebuilt binary is x86-64; arm64 needs `--build-from-source` |
|
|
| `sudo` / root | For `apt install`, `setcap` on the FIPS binary, and writing to `/usr/local` |
|
|
| Internet access | To download the binary, apt packages, and the FIPS source |
|
|
|
|
Tor and FIPS are **installed by default** (not optional). If either is absent at runtime the browser degrades gracefully — clearnet still works, `.onion`/`.fips` show an error page — but the installer sets them up so everything works out of the box.
|
|
|
|
---
|
|
|
|
## Build
|
|
|
|
Requires Debian 13 (trixie) or similar with WebKitGTK 4.1 dev headers:
|
|
|
|
```bash
|
|
sudo apt install libwebkit2gtk-4.1-dev
|
|
make
|
|
./browser.sh start [url] # build + launch (detached, won't hang terminal)
|
|
```
|
|
|
|
> **Note:** Always use `./browser.sh` to start/stop the browser. Running
|
|
> `./sovereign_browser` directly will hang the terminal because the GUI
|
|
> process keeps stdout/stderr open. See `./browser.sh --help` or
|
|
> [`.roo/agents.md`](.roo/agents.md) for details.
|
|
|
|
## Command-line flags
|
|
|
|
Run `./sovereign_browser --help` for the full list. Flags are parsed before
|
|
GTK init, so they don't conflict with GTK's own options. Flags override
|
|
`~/.sovereign_browser/settings.conf` for the current run only (nothing is
|
|
written to disk).
|
|
|
|
### Browser / Startup
|
|
|
|
| Flag | Description |
|
|
|---|---|
|
|
| `[URL...]` / `--url <url>` | Open URL(s) in tabs at startup (repeatable) |
|
|
| `--new-tab-url <url>` | Override the default new-tab URL |
|
|
| `--no-session-restore` | Skip session restore for this run |
|
|
| `--session-restore` | Force session restore even if disabled |
|
|
| `--max-tabs <n>` | Override max simultaneous tabs |
|
|
| `-V, --version` | Print version and exit |
|
|
| `-h, --help` | Show help and exit |
|
|
|
|
### Agent Server
|
|
|
|
| Flag | Description |
|
|
|---|---|
|
|
| `--port <port>` | Override agent MCP server port (default 17777) |
|
|
| `--no-agent` | Disable the agent server for this run |
|
|
| `--agent` | Force-enable the agent server |
|
|
| `--agent-origin <origin>` | Allowed origin (repeatable) |
|
|
|
|
### Login (skips the GTK login dialog)
|
|
|
|
Specify `--login-method` to bypass the interactive login dialog. The method
|
|
string matches the MCP `login` tool. Method-specific flags provide
|
|
credentials.
|
|
|
|
| Flag | Description |
|
|
|---|---|
|
|
| `--login-method <m>` | `generate\|local\|seed\|readonly\|nip46\|nsigner` |
|
|
| `--nsec <nsec1...>` | (local) nsec bech32 private key |
|
|
| `--privkey <hex>` | (local) 64-char hex private key |
|
|
| `--mnemonic <words>` | (seed) BIP-39 mnemonic, quoted |
|
|
| `--account <n>` | (seed) BIP-44 account index (default 0) |
|
|
| `--npub <npub1...>` | (readonly) npub bech32 public key |
|
|
| `--pubkey <hex>` | (readonly) 64-char hex pubkey |
|
|
| `--bunker <url>` | (nip46) `bunker://` URL |
|
|
| `--nsigner-transport <t>` | (nsigner) `serial\|unix\|tcp\|qrexec` |
|
|
| `--nsigner-device <path>` | (nsigner) device path / socket / host:port / qube |
|
|
| `--nsigner-service <name>` | (nsigner) qrexec service name |
|
|
| `--nsigner-index <n>` | (nsigner) key index (default 0) |
|
|
| `--no-save-identity` | Do not persist identity to disk |
|
|
| `--login-timeout <ms>` | Override agent login timeout (GTK dialog path) |
|
|
|
|
### Diagnostics
|
|
|
|
| Flag | Description |
|
|
|---|---|
|
|
| `-v, --verbose` | Increase log verbosity (repeatable) |
|
|
| `-q, --quiet` | Suppress non-error log output |
|
|
|
|
### Examples
|
|
|
|
```bash
|
|
# Basic usage (via browser.sh — recommended)
|
|
./browser.sh start https://example.com
|
|
|
|
# Generate a fresh key, skip the login dialog, open a page
|
|
./browser.sh start --login-method generate --url https://example.com
|
|
|
|
# Local key from env, custom agent port
|
|
./browser.sh start --login-method local --nsec "$NSEC" --port 18888
|
|
|
|
# Read-only (npub), no agent server, two tabs
|
|
./browser.sh start --login-method readonly --npub npub1... \
|
|
--no-agent --url https://a.com --url https://b.com
|
|
|
|
# Open a local website (no web server needed)
|
|
./browser.sh start --login-method generate \
|
|
--url "file:///path/to/website/index.html"
|
|
```
|
|
|
|
## Architecture (summary)
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────┐
|
|
│ sovereign_browser host (C99) │
|
|
│ ┌─────────┐ ┌──────────┐ ┌────────────────────┐ │
|
|
│ │ UI / │ │ Request │ │ Nostr signer shim │ │
|
|
│ │ tabs │ │ router │ │ (nostr_core_lib → │ │
|
|
│ │ URL bar │ │ │ │ n_signer socket) │ │
|
|
│ └─────────┘ └────┬─────┘ └─────────┬──────────┘ │
|
|
│ │ │ │
|
|
│ ┌──────────┼───────────┬───────┘ │
|
|
│ ▼ ▼ ▼ │
|
|
│ http/https fips:// nostr:// │
|
|
│ (WebKit net) (FIPS TUN) (relays) │
|
|
└─────────────────────────────────────────────────────┘
|
|
│
|
|
▼
|
|
┌─────────────────────────────────────────────────────┐
|
|
│ WebKitGTK (system lib, ~35 MB) │
|
|
│ WebCore renderer + JavaScriptCore + libsoup net │
|
|
└─────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
Full architecture, engine comparison, and roadmap in
|
|
[`docs/architecture.md`](docs/architecture.md).
|
|
|
|
### Custom URI scheme layer
|
|
|
|
The browser registers custom URI schemes via
|
|
`webkit_web_context_register_uri_scheme()`. This is the **network/content
|
|
layer** — it controls what bytes get loaded into the web view. One
|
|
infrastructure, multiple uses:
|
|
|
|
| Scheme | Purpose | Status |
|
|
|--------|---------|--------|
|
|
| `sovereign://nostr/*` | `window.nostr` bridge — web pages call `fetch('sovereign://nostr/signEvent')` to sign via the C-side `nostr_signer_t` | ✅ Working |
|
|
| `sovereign://settings`, `sovereign://bookmarks`, `sovereign://profile` | Browser-internal pages (like `chrome://settings`) | ✅ Working |
|
|
| `sovereign://agents/chat`, `sovereign://agents/config` | Agent chat and configuration pages | ✅ Working |
|
|
| `fips://` / `*.fips` | Route to FIPS mesh nodes via TUN interface | Planned |
|
|
| `nostr://` | Fetch Nostr events from relays, render as HTML | Planned |
|
|
|
|
A `WebKitWebExtension` (separate `.so` loaded into the web process) will be
|
|
added later for the **script manipulation layer** — security stripping
|
|
(CORS/SOP removal), synchronous NIP-07 calls, and content injection. The URI
|
|
scheme and WebExtension serve different layers and will coexist. See
|
|
[`plans/nostr-login-integration.md`](plans/nostr-login-integration.md) for the
|
|
full decision rationale.
|
|
|
|
### Nostr login
|
|
|
|
Login is a native GTK dialog (not a web page) that calls
|
|
[`nostr_core_lib`](https://github.com/laantungir/nostr_core_lib) directly.
|
|
Supported methods:
|
|
|
|
| Method | nostr_core_lib API |
|
|
|--------|-------------------|
|
|
| Local key (nsec) | `nostr_signer_local()`, `nostr_decode_nsec()` |
|
|
| Seed phrase (BIP-39) | `nostr_derive_keys_from_mnemonic()` |
|
|
| Read-only (npub) | `nostr_decode_npub()` |
|
|
| NIP-46 remote signer | `nostr_nip46_client_session_init()` |
|
|
| n_signer hardware | `nostr_signer_nsigner_serial/unix/tcp/qrexec()` + `nostr_signer_nsigner_set_nostr_index()` |
|
|
|
|
See [`plans/nostr-login-integration.md`](plans/nostr-login-integration.md) for
|
|
the full implementation plan.
|
|
|
|
### Browser tabs
|
|
|
|
The browser supports multiple tabs via a `GtkNotebook`. Each tab has its own
|
|
toolbar (hamburger menu + URL entry) and `WebKitWebView`. All tabs share a
|
|
single `WebKitWebContext`, so the `sovereign://` Nostr bridge, security
|
|
settings, and TLS policy apply to every tab automatically.
|
|
|
|
**Tab features:**
|
|
|
|
- New tab: `Ctrl+T` or the `+` button at the end of the tab strip
|
|
- Close tab: `Ctrl+W`, per-tab close button, or middle-click on the tab label
|
|
- Switch tabs: `Ctrl+Tab` / `Ctrl+Shift+Tab`, `Ctrl+PageUp` / `Ctrl+PageDown`
|
|
- Focus URL bar: `Ctrl+L`
|
|
- Right-click tab context menu: New Tab, Close Tab, Close Other Tabs, Close
|
|
Tabs to the Right, Duplicate Tab, Reload Tab
|
|
- Drag tabs to reorder
|
|
- Tab titles update from page load
|
|
- Session save/restore: open tabs are saved on exit and restored on next
|
|
launch (configurable in Settings)
|
|
|
|
**Settings dialog** (hamburger menu → Settings…):
|
|
|
|
- Restore session on startup (default: on)
|
|
- New tab URL (default: `https://example.com`)
|
|
- Tab bar position: Top / Bottom / Left / Right (default: Top)
|
|
- Show tab close buttons (default: on)
|
|
- Middle-click to close tab (default: on)
|
|
- Ctrl+Tab to switch tabs (default: on)
|
|
- Maximum tabs (default: 50)
|
|
- Allow drag to reorder tabs (default: on)
|
|
|
|
Settings are persisted to `~/.sovereign_browser/settings.conf`. Session state
|
|
is saved to `~/.sovereign_browser/session.txt`.
|
|
|
|
See [`plans/browser-tabs.md`](plans/browser-tabs.md) for the full
|
|
implementation plan.
|
|
|
|
### Local file browsing
|
|
|
|
sovereign_browser is designed to run websites directly from local files —
|
|
open an `index.html` from its directory and navigate as if it were served
|
|
over HTTP. No web server required. This is a deliberate design choice:
|
|
security is moved up to the Qube level, so the browser doesn't need the
|
|
traditional security restrictions (same-origin policy, CORS) that would
|
|
block local-file web apps.
|
|
|
|
**What works on `file://` pages:**
|
|
|
|
- **Relative links** between pages — `index.html` → `about.html`,
|
|
`subdir/page.html`, `../index.html`, `../../../deep/page.html`
|
|
- **Cross-origin access** — all `file://` URLs are treated as same-origin.
|
|
Iframes can access their parent's DOM, `window.open()` popups are
|
|
accessible, and `fetch()`/XHR work across directories.
|
|
- **`fetch()` and `XMLHttpRequest`** — load local JSON, text, and other
|
|
files via relative paths (returns `status=0`, the `file://` convention)
|
|
- **External resources** — CSS stylesheets, JavaScript files, SVG images,
|
|
favicons, `<picture>`/`srcset`, `<object>`/`<embed>`
|
|
- **Video and audio playback** — MP4 video and M4A audio play correctly
|
|
with full duration/dimension metadata
|
|
- **All browser storage** — `localStorage`, `sessionStorage`, `cookies`,
|
|
and `IndexedDB` all work fully (open, upgrade, put, get, count)
|
|
- **`history.pushState`/`replaceState`** — SPA-style routing works on
|
|
`file://` URLs
|
|
- **Query strings and hash fragments** — preserved in `location.href`,
|
|
accessible via `location.search`/`location.hash`
|
|
- **URL-encoded filenames** — `encoded%20name.html` (file on disk:
|
|
`encoded name.html`) loads correctly
|
|
- **Form submissions** — GET forms append query strings to the target
|
|
page; POST forms navigate (body silently dropped, no server)
|
|
- **`window.open()`** — opens local pages in new tabs
|
|
- **ES Modules** — dynamic `import()` works with local module files
|
|
- **Web Workers and Shared Workers** — `new Worker()` and
|
|
`new SharedWorker()` with local scripts enable background computation
|
|
threads (including cross-tab shared workers)
|
|
- **WebAssembly** — `WebAssembly.instantiate()` works for compiled code
|
|
- **Cross-origin fetch to remote HTTPS** — `fetch('https://example.com')`
|
|
from a `file://` page works with no CORS blocking (confirms the
|
|
"deprecated web security" design goal)
|
|
- **Cross-origin remote resources** — remote `<script src>`,
|
|
`<link rel=stylesheet>`, and `<img>` from HTTPS CDNs all load correctly
|
|
|
|
**Known limitations (WebKit engine quirks, not bugs):**
|
|
|
|
- `fetch()` for missing files throws `Load failed` instead of returning an
|
|
error Response (no HTTP status codes on `file://`)
|
|
- `<video>`/`<audio>` `error` events don't fire for missing source files
|
|
(valid media works perfectly)
|
|
- Cache API (CacheStorage) rejects non-HTTP/HTTPS URLs — use IndexedDB
|
|
instead for local-file storage
|
|
- Service Workers don't work on `file://` (W3C spec requires HTTP/HTTPS) —
|
|
use Web Workers for background processing instead
|
|
|
|
**Test site:** A comprehensive multipage test website with 53 edge cases
|
|
is in [`tests/local-site/`](tests/local-site/index.html). See
|
|
[`tests/local-site/LOCAL-FILE-BROWSING-REPORT.md`](tests/local-site/LOCAL-FILE-BROWSING-REPORT.md)
|
|
for the full test report.
|
|
|
|
```bash
|
|
# Open a local website
|
|
./browser.sh start --login-method generate \
|
|
--url "file:///path/to/your/website/index.html"
|
|
```
|
|
|
|
### Agent tools (MCP server)
|
|
|
|
The browser embeds an MCP (Model Context Protocol) server using Streamable
|
|
HTTP transport. External AI agents can control the browser programmatically
|
|
via `http://localhost:17777/mcp`.
|
|
|
|
The server starts before the login dialog and remains available throughout
|
|
the browser's lifecycle. An agent can log in at any time: while the dialog
|
|
is showing, or after the browser is already running.
|
|
|
|
**100 tools available**, including:
|
|
|
|
- **Login**: `login_status`, `login`, `logout`, `switch_identity`
|
|
- **Navigation**: `open`, `back`, `forward`, `reload`, `get_url`, `get_title`
|
|
- **Snapshot & inspection**: `snapshot`, `get_text`, `get_html`, `get_attr`,
|
|
`eval`, `screenshot`, `screenshot_annotated`
|
|
- **Interaction**: `click`, `dblclick`, `fill`, `type`, `press`, `scroll`,
|
|
`hover`, `focus`, `select`, `check`, `uncheck`, `drag`
|
|
- **Find elements**: `find_role`, `find_text`, `find_label`, `find_placeholder`,
|
|
`find_alt`, `find_title`, `find_testid`
|
|
- **Tabs**: `tab_list`, `tab_new`, `tab_switch`, `tab_close`, `close`, `close_all`
|
|
- **Wait**: `wait`, `wait_for`, `wait_for_text`, `wait_for_url`, `wait_for_load`
|
|
- **Cookies & storage**: `cookies_get/set/clear`, `storage_local_*`, `storage_session_*`
|
|
- **Frames**: `frame_switch`, `frame_main`
|
|
- **Dialogs**: `dialog_accept`, `dialog_dismiss`, `dialog_status`
|
|
- **Debug**: `console`, `errors`, `highlight`
|
|
- **Files**: `upload`, `pdf`
|
|
|
|
**Example workflow:**
|
|
|
|
```bash
|
|
# 1. Login (or use --login-method on the command line)
|
|
curl -s -X POST http://localhost:17777/mcp \
|
|
-H 'Content-Type: application/json' \
|
|
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"login","arguments":{"method":"generate"}}}'
|
|
|
|
# 2. Open a page
|
|
curl -s -X POST http://localhost:17777/mcp \
|
|
-H 'Content-Type: application/json' \
|
|
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"open","arguments":{"url":"https://example.com"}}}'
|
|
|
|
# 3. Snapshot — get accessibility tree with element refs
|
|
curl -s -X POST http://localhost:17777/mcp \
|
|
-H 'Content-Type: application/json' \
|
|
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"snapshot","arguments":{}}}'
|
|
|
|
# 4. Click by ref
|
|
curl -s -X POST http://localhost:17777/mcp \
|
|
-H 'Content-Type: application/json' \
|
|
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"click","arguments":{"ref":"@e2"}}}'
|
|
```
|
|
|
|
See [`.roo/agents.md`](.roo/agents.md) for the full tool list and workflow
|
|
guide, and [`plans/agent-tools.md`](plans/agent-tools.md) for the
|
|
implementation plan.
|
|
|
|
## Roadmap
|
|
|
|
1. ✅ Base browser (WebKitGTK + C99, loads pages)
|
|
2. ✅ Browser tabs (GtkNotebook, per-tab toolbar, session restore, settings)
|
|
3. ✅ Nostr login (GTK dialog → nostr_core_lib → nostr_signer_t, 6 methods)
|
|
4. ✅ `window.nostr` injection (`sovereign://` URI scheme bridge)
|
|
5. ✅ Agent MCP server (100 tools, Streamable HTTP at `http://localhost:17777/mcp`)
|
|
6. ✅ Embedded web content (`sovereign://settings`, `bookmarks`, `profile`, `agents/chat`, `agents/config`)
|
|
7. ✅ Bookmarks, history, search, keyboard shortcuts, per-user profiles
|
|
8. ✅ Local file browsing (multipage websites from `file://` with no web server)
|
|
9. ⏳ Security strip (disable SOP/CORS, accept any cert, shared context)
|
|
10. ⏳ FIPS URI scheme (`fips://` / `*.fips` via WebKitGTK scheme handler)
|
|
11. ⏳ `nostr://` content scheme
|
|
12. Future: agent runtime (didactyl hosting), multi-window, FIPS-distributed
|
|
|
|
## License
|
|
|
|
MIT (to match nostr_core_lib / n_signer / didactyl).
|