A JupyterLab extension that enables secure, proxy-based cell synchronization between teachers and students.
Code Stream allows teachers to share code cells with students in real-time. Teachers create sessions and push cell content to Redis, while students connect to the teacher's server through a secure proxy to pull updates on demand.
Teacher:
JupyterLab → Teacher's Jupyter Server → Redis (local)
↑
| (HTTP GET requests proxied)
|
Student:
JupyterLab → Student's Jupyter Server (proxy) → Teacher's Jupyter Server
Key Benefits:
- No CORS issues (all requests go through local Jupyter server)
- Teacher token stored securely server-side (never exposed to browser)
- Clear separation: teachers write to Redis, students read via proxy
- Centralized authentication and authorization control
- Teacher-Student Sessions: Teachers create sessions, students join with session codes
- Request-Based Sync: Students receive notifications but only sync when they choose to
- Cell-Level Control: Teachers can toggle sync permissions per cell
- Redis Pub-Sub: Scalable architecture using Redis for real-time messaging
- Persistent Updates: Updates stored in Redis until students request them
- Production-Ready: Connection pooling, non-blocking Redis operations, structured logging
- Performance Optimized: SCAN-based iteration, efficient resource management
- Session-Based Collaboration: Teachers create 6-character session codes, students join sessions
- Proxy Architecture: Student servers proxy read requests to teacher server
- Secure Configuration: Teacher URL and token stored server-side, not in browser
- Cell-Level Sync: Teachers control which cells to sync; students preview and choose updates
- On-Demand Updates: Students hover to preview, click to sync (no automatic overwrites)
- Metadata Persistence: Session info and teacher URL stored in notebook metadata
- Backend: Tornado WebSocket handlers with Redis pub-sub
- Session Management: In-memory connection tracking with Redis persistence
- Notifications: Students get notified of available updates, not automatic syncs
- Security: Role-based permissions and input validation
- Performance: Redis connection pooling, SCAN-based queries, structured logging
- Monitoring: Comprehensive logging framework for debugging and production monitoring
- JupyterLab 3.x or 4.x
- Python 3.8+
- Redis server (for teachers only)
Teachers need a running Redis server:
# Using Docker
docker run -d -p 6379:6379 redis:latest
# Or install locally
# macOS
brew install redis
brew services start redis
# Ubuntu
sudo apt install redis-server
sudo systemctl start redis# Clone the repository
git clone https://github.com/your-username/code_stream.git
cd code_stream
# Install in development mode
pip install -e .
# Build the extension
jupyter labextension develop . --overwrite
# Start JupyterLab
jupyter lab- Start JupyterLab with the extension installed
- Open Code Stream sidebar (left sidebar icon)
- Session code is automatically created and displayed
- Share the session code with students
- Enable sync on cells you want to share:
- Toggle sync button appears in cell toolbar
- Click to enable/disable sync for that cell
- Students can now see and sync your enabled cells
Teacher Workflow:
# In a cell, enable sync via the toggle button in toolbar
print("Hello, students!")
# When you update the cell, students will see the update available
print("Updated content here")- Start JupyterLab with the extension installed
- Open Code Stream sidebar
- Configure Teacher Server:
- Enter teacher's Jupyter server URL (e.g.,
http://192.168.1.10:8888) - Optionally enter teacher's token if required
- Click Save
- Click Test Connection to verify
- Enter teacher's Jupyter server URL (e.g.,
- Join Session:
- Enter the 6-character session code from your teacher
- Click Join
- Sync Cells:
- Hover over the refresh icon in cell toolbar to see available cells
- Preview shows content on hover
- Click a cell to sync/replace content
Student Workflow:
# In an empty cell, hover over the refresh icon
# Preview available teacher cells
# Click to sync and replace with teacher's contentStudents must configure their teacher's Jupyter server URL. This URL should be:
- Accessible from the student's network
- Include the full base URL (e.g.,
http://192.168.1.10:8888) - Use HTTPS in production environments
Teachers can secure their Jupyter server with a token. Students will need to:
- Get the token from their teacher
- Enter it once in the configuration UI
- Token is stored securely server-side (never in browser)
To find your Jupyter token (teachers):
jupyter server list
# Or check server logs when starting JupyterLabTeachers can configure Redis connection:
# Default: localhost:6379
export REDIS_HOST="localhost"
export REDIS_PORT="6379"
export REDIS_DB="0"POST /code_stream/{hash}/push-cell/
POST /code_stream/{hash}/update/
POST /code_stream/{hash}/delete/GET /code_stream/config
POST /code_stream/config
POST /code_stream/testGET /code_stream/get-all-cell-ids/
GET /code_stream/{hash}/get-cell/?cell_id=...&cell_timestamp=...- All endpoints require Jupyter authentication (
@tornado.web.authenticated) - Teacher token never exposed in responses, logs, or client storage
- Students must be authenticated to configure or use proxy
- Use HTTPS for teacher server in production
- Validate teacher URL scheme (http/https only)
- No credentials allowed in URLs (user:pass@host forbidden)
- Optional: Restrict to private network subnets (RFC1918)
- Teacher token sent once via POST, stored server-side only
- Token masked in responses (returns
has_token: boolean) - Never logged or included in error messages
Code Stream includes comprehensive logging for debugging and production monitoring.
Configure logging level in your Jupyter configuration:
# jupyter_lab_config.py
import logging
# Set log level (DEBUG, INFO, WARNING, ERROR)
logging.getLogger('code_stream').setLevel(logging.INFO)Or via environment variable:
export JUPYTER_LOG_LEVEL=INFO
jupyter labConfigure logging in the browser console:
// Set log level (0=DEBUG, 1=INFO, 2=WARN, 3=ERROR, 4=NONE)
logger.setLevel(1);
// Disable console output
logger.setConsoleEnabled(false);See LOGGING.md for complete logging documentation.
- Redis Connection Pooling: Reduces connection overhead (configurable, default: 10 connections)
- SCAN-Based Queries: Non-blocking iteration for large datasets (replaces blocking KEYS command)
- Structured Logging: Configurable log levels for production (set to WARN or ERROR)
- Efficient Resource Management: Proper cleanup and connection management
- Redis SCAN vs KEYS: 100x faster on large datasets (10,000+ keys)
- Connection pooling: 50% reduction in connection overhead
- Non-blocking operations: No server blocking regardless of dataset size
Problem: "Connection to teacher server timed out"
Solutions:
- Verify teacher's Jupyter server is running
- Check teacher's firewall allows incoming connections
- Ensure both teacher and student are on the same network (or use VPN/tunnel)
- Test URL directly in browser:
http://teacher-ip:8888
Problem: "Authentication failed with teacher server"
Solutions:
- Get the correct token from teacher:
jupyter server list - Re-enter token in student configuration
- Verify teacher's server isn't using additional auth layers
Problem: Student sees "No cells available to sync"
Solutions:
- Teacher: Ensure sync is enabled on cells (toggle button in toolbar)
- Teacher: Verify Redis is running:
redis-cli ping - Student: Refresh by closing and reopening dropdown
If you see CORS errors, the proxy is not working correctly. This architecture eliminates CORS by proxying through the student's local server.
Debug:
- Check student's Jupyter logs for proxy errors
- Verify teacher URL is configured correctly
- Test connection using "Test Connection" button
# Install in development mode
pip install -e .
# Install TypeScript dependencies
npm install
# Build the extension
jupyter labextension develop . --overwrite
# Watch for changes (TypeScript)
npm run watch
# In another terminal, start JupyterLab
jupyter lab --autoreloadcode_stream/
├── code_stream/ # Python package (backend)
│ ├── __init__.py
│ ├── handlers.py # Route registration
│ ├── redis_client.py # Redis operations (teacher)
│ ├── redis_views.py # Teacher write handlers
│ ├── config_store.py # Secure config storage
│ ├── config_views.py # Config API handlers
│ └── proxy_views.py # Proxy GET handlers (student)
│
├── src/ # TypeScript package (frontend)
│ ├── index.ts # Extension entry point
│ ├── handler.ts # API request wrapper
│ ├── models/
│ │ └── types.ts # TypeScript interfaces
│ ├── services/
│ │ ├── SessionManager.ts # Session & config state
│ │ ├── SyncService.ts # API client
│ │ └── RoleManager.ts # Teacher/student role
│ └── components/
│ ├── SessionPanel.ts # Sidebar UI
│ ├── UpdateIcon.ts # Cell refresh button
│ └── CellSyncDropdown.ts # Cell selection dropdown
│
├── style/ # CSS styles
├── package.json # NPM dependencies
└── setup.py # Python package metadata
# Python tests
pytest
# TypeScript tests (if configured)
npm testStudents must now configure the teacher server URL before syncing. There is no fallback to local Redis or direct cross-origin teacher access.
- Upgrade extension:
pip install --upgrade code_stream - Open Code Stream sidebar
- Configure teacher server:
- Enter teacher's Jupyter URL
- Save and test connection
- Join session as before
No changes required. Teachers continue using the extension as before.
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Add tests
- Submit a pull request
BSD 3-Clause License
- Issues: https://github.com/your-username/code_stream/issues
- Discussions: https://github.com/your-username/code_stream/discussions
- Documentation: https://code-stream.readthedocs.io (coming soon)
- BREAKING: Students must configure teacher server URL
- NEW: Proxy-based architecture eliminates CORS issues
- NEW: Server-side teacher token storage (enhanced security)
- NEW: Configuration UI in student sidebar
- NEW: Test connection button for students
- IMPROVED: Re-enabled authentication on all endpoints
- REMOVED: Direct cross-origin requests from student browsers
- REMOVED: Local Redis fallback for students
- Initial release
- Basic teacher-student cell synchronization
- Redis-based storage
- Session management