Skip to content

Commit 97d6816

Browse files
authored
Merge pull request #2 from BandarLabs/refactor
Refactor codebase with modular architecture and multi-kernel support tested uninstall -> install -> prime gen with gemini
2 parents 41faf14 + 2f7f347 commit 97d6816

File tree

13 files changed

+1176
-206
lines changed

13 files changed

+1176
-206
lines changed

.env.example

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# CodeRunner Configuration Example
2+
# Copy this file to .env and modify as needed
3+
4+
# Jupyter Settings
5+
CODERUNNER_JUPYTER_HOST=127.0.0.1
6+
CODERUNNER_JUPYTER_PORT=8888
7+
CODERUNNER_JUPYTER_WS_URL=ws://127.0.0.1:8888
8+
9+
# Directory Settings
10+
CODERUNNER_SHARED_DIR=/app/uploads
11+
12+
# Execution Settings
13+
CODERUNNER_EXECUTION_TIMEOUT=300.0
14+
CODERUNNER_WEBSOCKET_TIMEOUT=1.0
15+
CODERUNNER_MAX_WAIT_JUPYTER=30
16+
17+
# FastMCP Settings
18+
CODERUNNER_FASTMCP_HOST=0.0.0.0
19+
CODERUNNER_FASTMCP_PORT=8222
20+
21+
# Logging Settings
22+
CODERUNNER_LOG_LEVEL=INFO
23+
CODERUNNER_LOG_FORMAT=%(asctime)s - %(levelname)s - %(message)s
24+
25+
# Resource Settings (optional)
26+
# CODERUNNER_MAX_KERNEL_MEMORY=1G
27+
# CODERUNNER_MAX_KERNEL_CPU=1.0

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,4 @@ jupyter_runtime/
6363

6464
# Node modules (if any)
6565
node_modules/
66+
.aider*

Dockerfile

Lines changed: 43 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,66 @@
1-
# Use the specified standard Python 3.13.3 base image (Debian-based)
2-
FROM python:3.13.3
1+
# Multi-stage build for optimized image size
2+
FROM python:3.13.3 as builder
33

44
# Set environment variables
5-
ENV PYTHONDONTWRITEBYTECODE 1
6-
ENV PYTHONUNBUFFERED 1
5+
ENV PYTHONDONTWRITEBYTECODE=1
6+
ENV PYTHONUNBUFFERED=1
77
ENV DEBIAN_FRONTEND=noninteractive
88

9-
# Set working directory
10-
WORKDIR /app
11-
12-
# Install system dependencies INCLUDING systemd
9+
# Install build dependencies
1310
RUN apt-get update && apt-get install -y --no-install-recommends \
14-
systemd \
15-
sudo \
16-
curl \
17-
iproute2 \
18-
ffmpeg \
19-
bash \
2011
build-essential \
21-
procps \
22-
openssh-client \
23-
openssh-server \
24-
jq \
25-
kmod \
26-
&& apt-get clean && rm -rf /var/lib/apt/lists/*
27-
12+
&& rm -rf /var/lib/apt/lists/*
2813

2914
# Upgrade pip
3015
RUN python -m pip install --no-cache-dir --upgrade pip
3116

32-
# Copy requirements file
33-
COPY ./requirements.txt /app/requirements.txt
17+
# Copy requirements and install Python dependencies
18+
COPY requirements.txt /tmp/requirements.txt
19+
RUN pip install --no-cache-dir --user -r /tmp/requirements.txt
3420

35-
# Install Python dependencies
36-
RUN pip install --no-cache-dir -r requirements.txt
21+
# Runtime stage
22+
FROM python:3.13.3-slim
3723

24+
# Set environment variables
25+
ENV PYTHONDONTWRITEBYTECODE=1
26+
ENV PYTHONUNBUFFERED=1
27+
ENV DEBIAN_FRONTEND=noninteractive
28+
ENV PATH="/root/.local/bin:$PATH"
3829

39-
# Install the bash kernel spec for Jupyter (not working with uv)
40-
RUN python -m bash_kernel.install
30+
# Install runtime dependencies and tini for proper signal handling
31+
RUN apt-get update && apt-get install -y --no-install-recommends \
32+
curl \
33+
jq \
34+
tini \
35+
&& rm -rf /var/lib/apt/lists/*
4136

37+
# Set working directory
38+
WORKDIR /app
4239

43-
# Copy the application code (server.py)
44-
COPY ./server.py /app/server.py
40+
# Copy Python packages from builder stage
41+
COPY --from=builder /root/.local /root/.local
4542

46-
# Create application/jupyter directories
47-
RUN mkdir -p /app/uploads /app/jupyter_runtime
43+
# Install the bash kernel spec for Jupyter
44+
RUN python -m bash_kernel.install
4845

49-
# # Generate SSH host keys
50-
# RUN ssh-keygen -A
46+
# Copy application code
47+
COPY server.py config.py jupyter_client.py /app/
5148

52-
# Clean systemd machine-id
53-
RUN rm -f /etc/machine-id && touch /etc/machine-id
49+
# Create application directories
50+
RUN mkdir -p /app/uploads /app/jupyter_runtime
5451

55-
# --- Set environment variables for the application ---
56-
ENV FASTMCP_HOST="0.0.0.0"
57-
ENV FASTMCP_PORT="8222"
52+
# Copy the entrypoint script
53+
COPY entrypoint.sh /entrypoint.sh
54+
RUN chmod +x /entrypoint.sh
5855

56+
# Set environment variables for the application
57+
ENV CODERUNNER_FASTMCP_HOST="0.0.0.0"
58+
ENV CODERUNNER_FASTMCP_PORT="8222"
59+
ENV CODERUNNER_JUPYTER_HOST="0.0.0.0"
60+
ENV CODERUNNER_JUPYTER_PORT="8888"
5961

6062
# Expose the FastAPI port
61-
EXPOSE 8222
62-
63-
# Start the FastAPI application
64-
# CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8002", "--workers", "1", "--no-access-log"]
65-
66-
67-
# Copy the entrypoint script into the image
68-
COPY entrypoint.sh /entrypoint.sh
69-
70-
# Make the entrypoint script executable
71-
RUN chmod +x /entrypoint.sh
63+
EXPOSE 8222 8888
7264

73-
# Use the entrypoint script
74-
ENTRYPOINT ["/entrypoint.sh"]
65+
# Use tini for proper signal handling
66+
ENTRYPOINT ["tini", "--", "/entrypoint.sh"]

README.md

Lines changed: 173 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99

1010
CodeRunner is an MCP (Model Context Protocol) server that executes AI-generated code in a sandboxed environment on your Mac using Apple's native [containers](https://github.com/apple/container).
1111

12-
**Key use case:** Process your local files (videos, images, documents, data) with remote LLMs like Claude or ChatGPT without uploading your files to the cloud. The LLM generates code that runs locally on your machine to analyze, transform, or process your files.
12+
**Key use case:** Process your local files (videos, images, documents, data) with remote LLMs like Claude or ChatGPT without uploading your files to the cloud. The LLM generates Python code or bash scripts that run locally on your machine to analyze, transform, or process your files.
1313

1414
## What CodeRunner Enables
1515

@@ -21,6 +21,7 @@ CodeRunner is an MCP (Model Context Protocol) server that executes AI-generated
2121
| Copy/paste scripts to run elsewhere | Code runs immediately, shows output/files |
2222
| LLM analyzes text descriptions of files | LLM directly processes your actual files |
2323
| Manage Python environments and packages | Pre-configured environment ready to use |
24+
| Limited to one programming language | Supports both Python and Bash execution |
2425

2526
## Quick Start
2627

@@ -140,15 +141,185 @@ From [@apple/container](https://github.com/apple/container/blob/main/docs/techni
140141
## Architecture
141142

142143
CodeRunner consists of:
143-
- **Sandbox Container:** Isolated execution environment with Jupyter kernel
144+
- **Sandbox Container:** Isolated execution environment with Python and Bash Jupyter kernels
144145
- **MCP Server:** Handles communication between AI models and the sandbox
146+
- **Multi-Kernel Support:** Automatically routes Python and Bash code to appropriate kernels
145147

146148
## Examples
147149

148150
The `examples/` directory contains:
149151
- `openai-agents` - Example OpenAI agents integration
150152
- `claude-desktop` - Example Claude Desktop integration
151153

154+
## Development
155+
156+
### Running Locally
157+
158+
1. **Install dependencies:**
159+
```bash
160+
pip install -r requirements.txt
161+
```
162+
163+
2. **Set up configuration:**
164+
```bash
165+
cp .env.example .env
166+
# Edit .env with your preferred settings
167+
```
168+
169+
3. **Run tests:**
170+
```bash
171+
python -m pytest tests/ -v
172+
```
173+
174+
4. **Run the server:**
175+
```bash
176+
python server.py
177+
```
178+
179+
### Available MCP Tools
180+
181+
CodeRunner provides the following MCP tools for AI models:
182+
183+
1. **`execute_python_code`** - Execute Python code in a persistent Jupyter kernel
184+
```
185+
execute_python_code(command="print('Hello, World!')")
186+
```
187+
188+
2. **`execute_bash_code`** - Execute Bash commands in a persistent Jupyter bash kernel
189+
```
190+
execute_bash_code(command="ls -la && echo 'Directory listing complete'")
191+
```
192+
193+
3. **`get_kernel_status`** - Check the status of available kernels
194+
```
195+
get_kernel_status()
196+
```
197+
198+
### Usage Examples
199+
200+
**Python Code Execution:**
201+
```python
202+
# Data analysis
203+
execute_python_code("""
204+
import pandas as pd
205+
import matplotlib.pyplot as plt
206+
207+
# Create sample data
208+
data = {'x': [1, 2, 3, 4, 5], 'y': [2, 4, 6, 8, 10]}
209+
df = pd.DataFrame(data)
210+
print(df.describe())
211+
""")
212+
```
213+
214+
**Bash Script Execution:**
215+
```bash
216+
# File operations
217+
execute_bash_code("""
218+
# Create directory structure
219+
mkdir -p /tmp/test_dir
220+
cd /tmp/test_dir
221+
222+
# Create files
223+
echo "Hello World" > hello.txt
224+
echo "Goodbye World" > goodbye.txt
225+
226+
# List files with details
227+
ls -la
228+
""")
229+
```
230+
231+
**Combined Usage:**
232+
```python
233+
# Use bash to prepare data, then Python to analyze
234+
execute_bash_code("curl -o data.csv https://example.com/data.csv")
235+
execute_python_code("""
236+
import pandas as pd
237+
df = pd.read_csv('data.csv')
238+
print(df.head())
239+
""")
240+
```
241+
242+
### Configuration
243+
244+
CodeRunner can be configured via environment variables with the `CODERUNNER_` prefix for consistency across all components (Python application, Docker container, and entrypoint script). See `.env.example` for available options:
245+
246+
- `CODERUNNER_JUPYTER_HOST`: Jupyter server host (default: 127.0.0.1)
247+
- `CODERUNNER_JUPYTER_PORT`: Jupyter server port (default: 8888)
248+
- `CODERUNNER_FASTMCP_HOST`: FastMCP server host (default: 0.0.0.0)
249+
- `CODERUNNER_FASTMCP_PORT`: FastMCP server port (default: 8222)
250+
- `CODERUNNER_EXECUTION_TIMEOUT`: Code execution timeout in seconds (default: 300)
251+
- `CODERUNNER_LOG_LEVEL`: Logging level (default: INFO)
252+
253+
### Testing
254+
255+
Run the test suite:
256+
```bash
257+
# Run all tests
258+
python -m pytest tests/
259+
260+
# Run specific test files
261+
python -m pytest tests/test_config.py -v
262+
263+
# Run tests with coverage (if installed)
264+
python -m pytest tests/ --cov=. --cov-report=html
265+
```
266+
267+
## Recent Changes (Refactor Branch)
268+
269+
### Major Refactoring Improvements
270+
271+
1. **Modularized Architecture**
272+
- Extracted Jupyter client logic into `jupyter_client.py`
273+
- Created centralized configuration system in `config.py`
274+
- Improved separation of concerns
275+
276+
2. **Enhanced Configuration Management**
277+
- Environment variable support with `CODERUNNER_` prefix
278+
- Centralized configuration with sensible defaults
279+
- Better local development support
280+
281+
3. **Improved Error Handling**
282+
- Custom exception classes for better error categorization
283+
- More robust WebSocket connection handling
284+
- Comprehensive logging and error reporting
285+
286+
4. **Container Optimizations**
287+
- Multi-stage Docker build for smaller images
288+
- Proper signal handling with `tini`
289+
- Better entrypoint script with error handling
290+
- Unified configuration with `CODERUNNER_` prefix across all components
291+
292+
5. **Multi-Kernel Support**
293+
- Added Bash kernel support alongside Python
294+
- New `execute_bash_code` MCP tool for shell commands
295+
- Kernel status monitoring with `get_kernel_status` tool
296+
297+
6. **Testing Framework**
298+
- Comprehensive test suite with pytest
299+
- Unit tests for configuration and Jupyter client
300+
- Mock-based testing for isolated components
301+
302+
7. **Code Quality Improvements**
303+
- Pinned dependency versions for reproducible builds
304+
- Cleaner, more maintainable code structure
305+
- Better documentation and type hints
306+
307+
### File Structure
308+
```
309+
coderunner/
310+
├── config.py # Configuration management
311+
├── jupyter_client.py # Jupyter WebSocket client
312+
├── server.py # Main FastMCP server
313+
├── requirements.txt # Pinned dependencies
314+
├── Dockerfile # Optimized multi-stage build
315+
├── entrypoint.sh # Improved container entrypoint
316+
├── .env.example # Configuration template
317+
├── pytest.ini # Test configuration
318+
└── tests/ # Test suite
319+
├── test_config.py
320+
└── test_jupyter_client.py
321+
```
322+
152323
## Contributing
153324

154325
We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.

0 commit comments

Comments
 (0)