Executor Architecture Overview
Source files
src/qtg/infrastructure/executors/__init__.pysrc/qtg/infrastructure/executors/registry.pysrc/qtg/infrastructure/executors/local_adapter.pysrc/qtg/infrastructure/executors/remote_proxy.pysrc/qtg/infrastructure/bootstrap.py
1. Architecture Overview
The Movement Guard (MG) v3 executor is a node-level execution engine. Each node in a movement plan is bound to one executor, and the executor advances node state through five lifecycle methods (preflight / prepare / submit / observe / recover).
Depending on the executor deployment model, they are divided into two categories:
Both classes implement the same
ExecutorProtocol interface, so the dispatcher/observer can use them without distinguishing between local and remote.
2. ExecutorProtocol
@runtime_checkable protocol defined in domain/protocols.py:
In addition, there are
cancel and close methods:
cancel: supported only by some executors (for example, CEX withdrawal cancellation)close: cleans up resources such as internal HTTP clients
3. LocalExecutorAdapter
File:infrastructure/executors/local_adapter.py
Wraps an in-process handler object with the ExecutorProtocol interface.
self._handler. Core behavior:
Note that the health check does not call the handler and always returns
ok: True.
4. RemoteExecutorProxy
File:infrastructure/executors/remote_proxy.py
A proxy that delegates executor calls to an external HTTP service.
4.1 Constructor
4.2 HTTP JSON Protocol
All calls are JSON requests in the formPOST {base_url}/{method}.
Note that the
submit body shape differs from the other methods. context and prepared_action are sent as separate keys, and additional kwargs such as sign_result are merged at the top level.
Auth header: if auth_token is configured, every request includes Authorization: Bearer {token}.
4.3 close behavior
Ifclient is injected externally, _owns_client = False and aclose() is not called on close. Cleanup happens only for internally created clients.
5. Executor Registry
File:infrastructure/executors/registry.py
Registers and retrieves executors from a module-level dict[str, object].
5.1 executor_binding and registry lookup
MovementRequestNode.executor_binding is stored in the DB as JSON and has the following shape:
get_executor(binding) receives this dict, it extracts binding["executor_key"] and looks it up in the registry. A plain string is also allowed.
5.2 Built-in executor key list
The Stargate executor ships in the Pro distribution and is registered through the package/loader gate — it is excluded from the OSS distribution. Lighter registration for
lighter_secure_withdraw requires the Pro loader, an AwsKmsEvmSigner, configured L1 owner, contract, and account index, successful KMS address resolution with owner == KMS address, and L1 RPC via an explicit Lighter endpoint or EVM endpoints.
6. Health Check Protocol
Local
Remote
/health endpoint and returns the response JSON as-is. If the connection fails, the exception propagates.
Registry-level health check
Inapplication/services/registry.py, the system iterates over all executors via iter_executors() and calls health() on each one. It records the status in the DB as ExecutorRegistryEntry rows.
7. Bootstrap Process
File:infrastructure/bootstrap.py
When bootstrap_runtime(settings=settings) is called, executors and probes are registered in the following order:
MG_EVM_RPC_ENDPOINTS_JSON is empty (no EVM endpoints). CEX and observe executors are always registered. CCIP is gated by ccip_enabled and registered before the EVM-endpoint guard. Stargate additionally requires MG_STARGATE_ENABLED and the Pro package/loader gate; Lighter uses the same package/loader gate. Both are absent from the OSS distribution.
8. Guide to Adding a New Executor
8.1 Local Executor
- Implement a handler class. At minimum, five methods are required:
- Wrap it with
LocalExecutorAdapterand register it in the registry:
- Add the registration call to
bootstrap_runtime()inbootstrap.py.
8.2 Remote Executor
-
Implement six endpoints in the remote service:
POST /preflight,POST /prepare,POST /submit,POST /observe,POST /recover,GET /health
-
Register it in the registry with
RemoteExecutorProxy:
Related Documents
- CEX Lane Executors
- CCTP Lane Executors
- Observe Probes
- Domain Protocols (ExecutionContext, ExecutionResult, PreparedAction)