Design and Architecture

This page goes deeper into how Astra is structured internally. If you just want to use the library, Core Concepts is enough. This page is for contributors and people who want to understand the design decisions.

Layer diagram

+---------------------------------------------------+
| Your application (app.py / bot.py)    |
+---------------------------------------------------+
| astra.Client          |
| .chat .group .account (method mixins)  |
+---------------------------------------------------+
| astra.protocol.ProtocolBridge (gateway.py)  |
| - call() - ensure_bridge() - diagnostics  |
+---------------------------------------------------+
| astra.core.bridge.* (domain bridges)   |
| chat.py group.py media.py account.py ... |
+---------------------------------------------------+
| astra.protocol.js_engine (injected JS)   |
+---------------------------------------------------+
| Playwright (page.evaluate)      |
+---------------------------------------------------+
| Chromium browser --> WhatsApp Web servers  |
+---------------------------------------------------+

Module breakdown

astra.client

The public-facing Client class and its supporting infrastructure:

  • client.py – the main Client class with start(), stop(),

run_forever(), and the startup banner.

  • authenticator.py – QR and phone-pairing authentication flow.

  • sync_engine.py – background heartbeat, stall detection, reconnection.

  • lifecycle.py – state machine (OFFLINE, STARTING, READY, etc.).

  • session_store.py – cookie and local-storage persistence.

  • methods/ – chat, group, account method mixins.

astra.protocol

The transport layer between Python and JavaScript:

  • gateway.pyProtocolBridge.call() with automatic retry,

error classification, and self-healing.

  • js_engine.py – the JavaScript source injected into WhatsApp Web.

  • validators.py – JID and input validation.

astra.core.bridge

Domain-specific bridges that translate high-level Python calls into specific JS method invocations:

  • chat.py, group.py, media.py, account.py,

contact.py, privacy.py, status.py, diagnostic.py

astra.errors

Structured error handling:

  • codes.py – 71 error codes in 8 categories.

  • base.pyAstraError with severity, retryable, cause, to_dict.

  • exceptions.py – 40+ typed exception classes.

astra.events

The event pipeline:

  • dispatcher.py – routes browser events to registered handlers.

  • emitter.py – fire-and-forget event emission.

  • filters.py – composable message matchers (command, regex, etc.).

  • context.pyEventContext wrapping each incoming event.

astra.models

Data classes representing WhatsApp entities:

  • message.pyMessage with reply, react, delete helpers.

  • chat.pyChat with title, participants, metadata.

  • user.pyUser and JID.

  • enums.pyClientStatus and other enumerations.

astra.connection

Browser lifecycle:

  • browser_manager.py – launch, lock, crash recovery, console relay.

  • page_controller.py – navigation, cache clearing, page health.

  • reconnect_policy.py – exponential backoff with jitter.

Error classification in the gateway

When a JS bridge call fails, the gateway doesn’t just re-raise the raw Playwright error. It classifies it:

JS exception text   --> Python exception
-------------------------------------------------------
"method not found"   --> BridgeMethodNotFoundError
"timeout"     --> MessageTimeoutError
"rate" / "too many"   --> RateLimitedError
"target closed" / "page"  --> ConnectionLostError
anything else    --> BridgeCallError

This means your code can catch specific errors and react appropriately.

Self-healing bridge

The bridge connection can break for several reasons: page reload, navigation, Chromium garbage collection. Astra handles this automatically:

  1. A call() fails with a recoverable error.

  2. The gateway calls ensure_bridge() to check if the JS engine is alive.

  3. If not, it re-injects the engine and retries the call once.

  4. If that also fails, it raises a typed exception.

The SyncEngine adds another layer: if no events arrive for 90 seconds, it assumes the bridge is stale and triggers a recovery cascade (re-bind listeners, re-init Store, full restart).

Design principles

No protocol RE.

Astra never reverse-engineers the WhatsApp binary protocol. It drives the official web client, which means it stays compatible as WhatsApp updates.

Fail loud, fail typed.

Every failure path has a named exception with a code, hint, and retry flag. No bare except Exception blocks in the library.

Async all the way.

Every I/O operation is async. No sync wrappers, no threading hacks.

Single source of truth.

Error codes live in codes.py. Version lives in pyproject.toml and is synced to __init__.__version__.