private, distributed state made effortless

pip install syft-widget
import syft_widget as sw

class LiveClock(sw.DynamicWidget):

    def get_endpoints(self):
    
        @self.endpoint("/api/time")
        def get_time():
            import time
            now = time.strftime("%H:%M:%S")
            return {"time": now}

    def get_template(self):
        return '''
Time:<span data-field="time">{time}</span>
        '''
        
clock = LiveClock("Live Clock", height="50px")
clock
Time: 14:35:22

Why We Built This

working with private, distributed state shouldn't be hard

📁 Distributed state is files

Decentralized systems need maximum interoperability - zillions of computers must collaborate without centralizing data. Because of Unix, files are the universal language that lets everyone work together.

🚫 Jupyter widgets hate files

Jupyter struggles to show live file state due to Python / JavaScript isolation. Traditional widgets can't efficiently watch files or handle real-time updates.

🚀 syft-widget bridges the gap

We spawn local servers that watch files directly, serve live updates via HTTP, and render in protected iframes - making file-backed UIs effortless.

See It In Action

with file-backed widgets — private, distributed state can be effortless

Under the Hood

file-backed widgets for distributed systems

# 🚀 Instant Load + Live Updates:
#
#  t=0ms: Python renders template with checkpoint data
#  ┌─────────────────┐         ┌──────────────────┐
#  │ Widget.__init__ │────────►│ {time} → "14:30" │ (instant!)
#  └─────────────────┘         └──────────────────┘
#           │                           │
#           ▼                           ▼
#  t=50ms: Spawn server        ┌──────────────────┐
#  ┌─────────────────┐         │  iframe renders  │
#  │ FastAPI server  │         │   HTML + CSS     │
#  │  watches files  │         └──────────────────┘
#  └─────────────────┘                  │
#           │                           ▼
#           ▼                  ┌──────────────────┐
#  t=100ms: Server ready       │ JS finds server  │
#  ┌─────────────────┐         │ via port scan    │
#  │ /api/time →     │◄────────┤ (8000-8010)      │
#  │ {"time":"14:31"}│         └──────────────────┘
#  └─────────────────┘                  │
#           ▲                           ▼
#           │                  ┌──────────────────┐
#    Files change              │ Live updates via │
#    FSEvents/inotify          │ data-field="time"│
#           │                  └──────────────────┘
#           │                           ▲
#           └───────────────────────────┘

# The magic: Users see content instantly, servers persist across reloads
widget = YourWidget()  # Instant display, then live updates

The Complete API

resilient widgets for the private data internet

Create widgets ready to manage private, distributed state

import syft_widget as sw

class MyWidget(sw.DynamicWidget):
    def get_endpoints(self):
        @self.endpoint("/api/data")
        def get_data():
            return {"value": read_file()}
    
    def get_template(self):
        return '''<div data-field="value">{value}</div>'''

# Create with options
widget = MyWidget(
    server_name="my_server",    # Optional name
    height="200px",             # Widget height
    update_interval=1000,       # Refresh rate (ms)
    expiration_seconds=3600     # Auto-cleanup
)

Server Access via syft-serve

import syft_serve as ss

# List all servers
ss.servers

# Access specific server
server = ss.servers['my_server']

# Server properties
server.status      # "running"
server.url         # http://localhost:8001
server.uptime      # "2h 15m"
server.endpoints   # ["/api/data"]

# Control servers
server.terminate()
ss.servers.terminate_all()

Logs & Debugging

# Via widget's server property
widget.server.stdout.tail(20)
widget.server.stderr.tail(20)

# Stream logs in real-time
widget.server.stdout.follow()

# Access underlying server
widget.server  # syft-serve server object

Advanced Features

# Widget with dependencies
widget = MyWidget(
    dependencies=['pandas', 'numpy'],
    force_new_server=True
)

# Widget properties
widget.server_name     # Server identifier
widget.update_interval # Refresh rate
widget.server         # Access underlying server

# Force restart if needed
widget._restart_server()
widget._stop_server()

try it out

experience syft-widget in jupyter notebook

open in colab