[object Object]

← back to Exo

[feat] Add an option to disable the worker (#1091)

839b67f318b6b5422b119b1a74e38883ca6f9ce1 · 2026-01-05 12:05:03 +0000 · Evan Quiney

## Motivation

Workerless machines can be used for networking without running any gpu
jobs - add a cli flag that adds this basic functionality.

## Changes

Adds the --no-worker cli flag

## Test Plan

### Manual Testing

Exo starts as expected

### Automated Testing

None

Files touched

Diff

commit 839b67f318b6b5422b119b1a74e38883ca6f9ce1
Author: Evan Quiney <evanev7@gmail.com>
Date:   Mon Jan 5 12:05:03 2026 +0000

    [feat] Add an option to disable the worker (#1091)
    
    ## Motivation
    
    Workerless machines can be used for networking without running any gpu
    jobs - add a cli flag that adds this basic functionality.
    
    ## Changes
    
    Adds the --no-worker cli flag
    
    ## Test Plan
    
    ### Manual Testing
    
    Exo starts as expected
    
    ### Automated Testing
    
    None
---
 src/exo/main.py | 32 +++++++++++++++++++++-----------
 1 file changed, 21 insertions(+), 11 deletions(-)

diff --git a/src/exo/main.py b/src/exo/main.py
index d6750a29..43d69aa5 100644
--- a/src/exo/main.py
+++ b/src/exo/main.py
@@ -28,7 +28,7 @@ from exo.worker.main import Worker
 @dataclass
 class Node:
     router: Router
-    worker: Worker
+    worker: Worker | None
     election: Election  # Every node participates in election, as we do want a node to become master even if it isn't a master candidate if no master candidates are present.
     election_result_receiver: Receiver[ElectionResult]
     master: Master | None
@@ -62,15 +62,19 @@ class Node:
         else:
             api = None
 
-        worker = Worker(
-            node_id,
-            session_id,
-            exo_shard_downloader(),
-            connection_message_receiver=router.receiver(topics.CONNECTION_MESSAGES),
-            global_event_receiver=router.receiver(topics.GLOBAL_EVENTS),
-            local_event_sender=router.sender(topics.LOCAL_EVENTS),
-            command_sender=router.sender(topics.COMMANDS),
-        )
+        if not args.no_worker:
+            worker = Worker(
+                node_id,
+                session_id,
+                exo_shard_downloader(),
+                connection_message_receiver=router.receiver(topics.CONNECTION_MESSAGES),
+                global_event_receiver=router.receiver(topics.GLOBAL_EVENTS),
+                local_event_sender=router.sender(topics.LOCAL_EVENTS),
+                command_sender=router.sender(topics.COMMANDS),
+            )
+        else:
+            worker = None
+
         # We start every node with a master
         master = Master(
             node_id,
@@ -100,8 +104,9 @@ class Node:
         async with self._tg as tg:
             signal.signal(signal.SIGINT, lambda _, __: self.shutdown())
             tg.start_soon(self.router.run)
-            tg.start_soon(self.worker.run)
             tg.start_soon(self.election.run)
+            if self.worker:
+                tg.start_soon(self.worker.run)
             if self.master:
                 tg.start_soon(self.master.run)
             if self.api:
@@ -209,6 +214,7 @@ class Args(CamelCaseModel):
     spawn_api: bool = False
     api_port: PositiveInt = 52415
     tb_only: bool = False
+    no_worker: bool = False
 
     @classmethod
     def parse(cls) -> Self:
@@ -246,6 +252,10 @@ class Args(CamelCaseModel):
             dest="api_port",
             default=52415,
         )
+        parser.add_argument(
+            "--no-worker",
+            action="store_true",
+        )
 
         args = parser.parse_args()
         return cls(**vars(args))  # pyright: ignore[reportAny] - We are intentionally validating here, we can't do it statically

← 47b8e0ce feat: remember last launch settings (model, sharding, instan  ·  back to Exo  ·  feat(macos-app): add custom namespace UI for cluster isolati 4f6fcd9e →