diff --git a/README.md b/README.md index 7f3ba8d..3ba81d7 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,15 @@ # Adaptive Multi-Protocol Browser -> Status: draft | Updated 2026-07-05 | Applies to: AMPB contributors and operators +> Status: draft | Updated 2026-07-07 | Applies to: AMPB contributors and operators Adaptive Multi-Protocol Browser, or AMPB, is a transport-aware browser shell. It routes URLs to the right network, adopts transports that are already healthy, and manages missing transports when configured to do so. +AMPB is Firefox-first for normal web browsing. The initial product should control a +hardened Firefox runtime, transport-specific profiles, and AMPB-owned transport setup +before graduating into a deeper Firefox or Tor Browser fork. + The first fixture is Wownero across clearnet, Tor, I2P, Gemini, and Reticulum-oriented targets generated by AMPG. Interactive fixtures include `ai-gen-bot` and the Medusa multi-tenant platform. @@ -56,6 +60,7 @@ python3 -m unittest discover -s tests - [Transport management](docs/transport-management.md) - [Test fixtures](docs/test-fixtures.md) - [Autodocs and drift gates](docs/autodocs.md) +- [Generated browser strategy](docs/generated/browser-strategy.md) ## Reusable checklist diff --git a/ampbrowser/config.py b/ampbrowser/config.py index 0346486..5598564 100644 --- a/ampbrowser/config.py +++ b/ampbrowser/config.py @@ -23,7 +23,7 @@ class ConfigError(ValueError): @dataclass(frozen=True) class AppConfig: state_dir: str = ".ampb" - default_engine: str = "system" + default_engine: str = "hardened-firefox" isolate_by_transport: bool = True transport_modes: dict[str, str] | None = None @@ -68,7 +68,7 @@ def _parse_config(data: dict[str, Any], path: Path) -> AppConfig: transports = _table(data, "transports", path) state_dir = _string(browser, "state_dir", ".ampb", path) - default_engine = _string(browser, "default_engine", "system", path) + default_engine = _string(browser, "default_engine", "hardened-firefox", path) isolate_by_transport = _bool(profiles, "isolate_by_transport", True, path) transport_modes = _transport_modes(transports, path) diff --git a/ampbrowser/docsgen.py b/ampbrowser/docsgen.py index 6c4a512..ef64184 100644 --- a/ampbrowser/docsgen.py +++ b/ampbrowser/docsgen.py @@ -4,7 +4,7 @@ from pathlib import Path from .adapters import ADAPTERS from .candidates import CANDIDATE_TRANSPORTS -from .metadata import ROUTE_RULES, TRANSPORT_DEFINITIONS +from .metadata import BROWSER_BACKENDS, ROUTE_RULES, TRANSPORT_DEFINITIONS from .platforms import PLATFORM_CAPABILITIES @@ -18,6 +18,7 @@ def generate_docs(root: Path, *, check: bool = False) -> list[Path]: GENERATED_DIR / "adapters.md": _adapters_doc(), GENERATED_DIR / "candidate-transports.md": _candidate_transports_doc(), GENERATED_DIR / "platform-capabilities.md": _platform_capabilities_doc(), + GENERATED_DIR / "browser-strategy.md": _browser_strategy_doc(), } changed: list[Path] = [] for rel_path, content in docs.items(): @@ -104,3 +105,16 @@ def _candidate_transports_doc() -> str: f"[source]({candidate.source}) | {candidate.note} |" ) return _header("Generated Candidate Transports") + "\n".join(rows) + "\n" + + +def _browser_strategy_doc() -> str: + rows = [ + "| Backend | Role | Status | Platforms | Launch Mode | Privacy Posture | Note |", + "| --- | --- | --- | --- | --- | --- | --- |", + ] + for backend in BROWSER_BACKENDS: + rows.append( + f"| `{backend.name}` | {backend.role} | `{backend.status}` | {backend.platforms} | " + f"{backend.launch_mode} | {backend.privacy_posture} | {backend.note} |" + ) + return _header("Generated Browser Strategy") + "\n".join(rows) + "\n" diff --git a/ampbrowser/metadata.py b/ampbrowser/metadata.py index 924ae28..627920b 100644 --- a/ampbrowser/metadata.py +++ b/ampbrowser/metadata.py @@ -20,6 +20,17 @@ class TransportDefinition: note: str +@dataclass(frozen=True) +class BrowserBackend: + name: str + role: str + status: str + platforms: str + launch_mode: str + privacy_posture: str + note: str + + ROUTE_RULES = ( RouteRule("*.onion", "tor", "tor", "route through Tor SOCKS"), RouteRule("*.i2p", "i2p", "i2p", "route through I2P HTTP proxy"), @@ -66,3 +77,51 @@ TRANSPORT_DEFINITIONS = ( "Adapter planned for resilient/private routing; physical/link-layer setup may require operator config.", ), ) + +BROWSER_BACKENDS = ( + BrowserBackend( + "hardened-firefox", + "primary web runtime", + "planned", + "desktop, android", + "managed profile, policy, and native transport launcher", + "strong baseline; track Firefox ESR and Tor Browser hardening choices", + "Default AMPB web runtime before a full browser fork.", + ), + BrowserBackend( + "tor-browser-compatible", + "tor-hardened target", + "planned", + "desktop, android", + "adopt, launch, or fork after transport contracts are stable", + "highest Tor web target; do not claim equivalence until Tor Browser patches are tracked", + "Path toward real Tor Browser-grade behavior for .onion browsing.", + ), + BrowserBackend( + "webkit-ios-shell", + "ios runtime", + "planned", + "ios", + "native shell with embedded transports and isolated web views", + "platform constrained; avoid clearnet fallback and isolate transport state", + "Required for App Store-style iOS builds outside special browser-engine entitlements.", + ), + BrowserBackend( + "gemini-native-viewer", + "alternate-web viewer", + "planned", + "desktop, android, ios", + "built-in fetch and render path", + "no web engine or shared browser storage required", + "Used for Gemini and similar lightweight document transports.", + ), + BrowserBackend( + "chromium-cef", + "prototype fallback", + "fallback", + "desktop", + "profile launcher only when Firefox path is blocked", + "not a Tor Browser privacy baseline", + "Allowed for experiments, but not the main privacy-browser strategy.", + ), +) diff --git a/docs/architecture.md b/docs/architecture.md index cc9df82..d30bacc 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -1,6 +1,6 @@ # Architecture -> Status: draft | Updated 2026-07-05 | Applies to: AMPB contributors and integrators +> Status: draft | Updated 2026-07-07 | Applies to: AMPB contributors and integrators AMPB is a browser orchestration layer for privacy, resilient-network, content-addressed, and alternate-web transports. It keeps the routing, transport management, and profile @@ -29,14 +29,22 @@ isolation decisions outside the browser engine until those contracts are stable. ## Browser Strategy -The first implementation should be a launcher and profile manager, not a browser-engine -fork. Tor Browser, Mullvad Browser, Firefox profiles, Chromium profiles, terminal Gemini -clients, local IPFS gateways, and future Reticulum-native viewers can all sit behind the same route and -transport contracts. +The first implementation should be Firefox-first without becoming a browser-engine fork +immediately. AMPB should control a hardened Firefox runtime, AMPB-owned profiles, +transport proxy policy, native transport setup, and health checks while the orchestration +contracts become stable. -The long-term browser can become more integrated once the orchestration surface is boring: -profile isolation is reliable, transport adoption is predictable, and generated fixtures -from AMPG can be opened without manual proxy setup. +Tor Browser compatibility is the high bar for `.onion` browsing. AMPB must not claim Tor +Browser equivalence until it tracks the relevant Tor Browser hardening, fingerprinting, +proxy, and update behavior. Chromium or CEF can remain a prototype fallback, but it is not +the main privacy-browser strategy. + +The long-term browser can become a deeper Firefox or Tor Browser fork once the +orchestration surface is reliable: profile isolation is predictable, transport adoption is +boring, and generated fixtures from AMPG open without manual proxy setup. + +Generated backend metadata lives in +[generated browser strategy](generated/browser-strategy.md). ## Relationship To AMPG diff --git a/docs/autodocs.md b/docs/autodocs.md index c5e7df4..cd61fd6 100644 --- a/docs/autodocs.md +++ b/docs/autodocs.md @@ -1,6 +1,6 @@ # Autodocs -> Status: draft | Updated 2026-07-05 | Applies to: AMPB maintainers +> Status: draft | Updated 2026-07-07 | Applies to: AMPB maintainers Public docs should stay concise and current. Code-owned behavior is documented from code, while manual docs explain stable concepts and operator-facing choices. @@ -19,7 +19,9 @@ Check for drift: python3 -m ampbrowser docs generate --check ``` -Generated files live under `docs/generated/` and must not be edited by hand. +Generated files live under `docs/generated/` and must not be edited by hand. They cover +route rules, active transports, browser backend strategy, adapter contracts, candidate +transports, and platform capabilities. ## Manual Docs diff --git a/docs/configuration.md b/docs/configuration.md index a5dc4dd..d89c865 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -1,6 +1,6 @@ # Configuration -> Status: draft | Updated 2026-07-05 | Applies to: AMPB users and package maintainers +> Status: draft | Updated 2026-07-07 | Applies to: AMPB users and package maintainers AMPB should work without a config file for common local setups. Explicit configuration is for changing defaults, pinning binary paths, choosing managed state directories, and @@ -27,7 +27,7 @@ Example configs live under `examples/`. ```toml [browser] -default_engine = "system" +default_engine = "hardened-firefox" state_dir = ".ampb" [transports.tor] diff --git a/docs/generated/browser-strategy.md b/docs/generated/browser-strategy.md new file mode 100644 index 0000000..f8b6116 --- /dev/null +++ b/docs/generated/browser-strategy.md @@ -0,0 +1,13 @@ +# Generated Browser Strategy + +> Status: generated | Updated by `python3 -m ampbrowser docs generate` | Applies to: AMPB + +This file is generated from code. Do not edit it by hand. + +| Backend | Role | Status | Platforms | Launch Mode | Privacy Posture | Note | +| --- | --- | --- | --- | --- | --- | --- | +| `hardened-firefox` | primary web runtime | `planned` | desktop, android | managed profile, policy, and native transport launcher | strong baseline; track Firefox ESR and Tor Browser hardening choices | Default AMPB web runtime before a full browser fork. | +| `tor-browser-compatible` | tor-hardened target | `planned` | desktop, android | adopt, launch, or fork after transport contracts are stable | highest Tor web target; do not claim equivalence until Tor Browser patches are tracked | Path toward real Tor Browser-grade behavior for .onion browsing. | +| `webkit-ios-shell` | ios runtime | `planned` | ios | native shell with embedded transports and isolated web views | platform constrained; avoid clearnet fallback and isolate transport state | Required for App Store-style iOS builds outside special browser-engine entitlements. | +| `gemini-native-viewer` | alternate-web viewer | `planned` | desktop, android, ios | built-in fetch and render path | no web engine or shared browser storage required | Used for Gemini and similar lightweight document transports. | +| `chromium-cef` | prototype fallback | `fallback` | desktop | profile launcher only when Firefox path is blocked | not a Tor Browser privacy baseline | Allowed for experiments, but not the main privacy-browser strategy. | diff --git a/examples/config.toml b/examples/config.toml index b6864bc..7fd9e3a 100644 --- a/examples/config.toml +++ b/examples/config.toml @@ -1,5 +1,5 @@ [browser] -default_engine = "system" +default_engine = "hardened-firefox" state_dir = ".ampb" [transports.tor] diff --git a/examples/i2p-disabled.toml b/examples/i2p-disabled.toml index be548f5..a4354db 100644 --- a/examples/i2p-disabled.toml +++ b/examples/i2p-disabled.toml @@ -1,5 +1,5 @@ [browser] -default_engine = "system" +default_engine = "hardened-firefox" state_dir = ".ampb" [transports.i2p] diff --git a/tests/test_browser_strategy.py b/tests/test_browser_strategy.py new file mode 100644 index 0000000..f8a1b14 --- /dev/null +++ b/tests/test_browser_strategy.py @@ -0,0 +1,24 @@ +from __future__ import annotations + +import unittest + +from ampbrowser.metadata import BROWSER_BACKENDS + + +class BrowserStrategyTest(unittest.TestCase): + def test_primary_backend_is_hardened_firefox(self) -> None: + primary = [backend for backend in BROWSER_BACKENDS if backend.role == "primary web runtime"] + + self.assertEqual(1, len(primary)) + self.assertEqual("hardened-firefox", primary[0].name) + self.assertIn("Firefox", primary[0].privacy_posture) + + def test_chromium_is_fallback_not_privacy_baseline(self) -> None: + chromium = next(backend for backend in BROWSER_BACKENDS if backend.name == "chromium-cef") + + self.assertEqual("fallback", chromium.status) + self.assertIn("not a Tor Browser", chromium.privacy_posture) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_config.py b/tests/test_config.py index 5f31e23..163028c 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -13,6 +13,7 @@ class ConfigTest(unittest.TestCase): config = load_config(Path(tmp)) self.assertEqual(".ampb", config.state_dir) + self.assertEqual("hardened-firefox", config.default_engine) self.assertEqual("adopt-or-prompt-manage", config.transport_mode("tor")) self.assertEqual(".ampb/profiles/tor", config.profile_path("tor")) diff --git a/tests/test_docsgen.py b/tests/test_docsgen.py index e90cb8c..e690456 100644 --- a/tests/test_docsgen.py +++ b/tests/test_docsgen.py @@ -16,6 +16,7 @@ class DocsGenTest(unittest.TestCase): self.assertEqual( { Path("docs/generated/adapters.md"), + Path("docs/generated/browser-strategy.md"), Path("docs/generated/candidate-transports.md"), Path("docs/generated/platform-capabilities.md"), Path("docs/generated/route-rules.md"),