Metadata-Version: 2.4
Name: nucl
Version: 0.2.0
Summary: Minimal ML experiment platform wrapping Azure ML, Vertex AI, and Vercel Sandbox
Project-URL: Homepage, https://github.com/lunit-io/nucl
Project-URL: Repository, https://github.com/lunit-io/nucl
Author-email: Lunit <sunghyun.cho@lunit.io>
License-Expression: MIT
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Requires-Python: >=3.11
Requires-Dist: click>=8.3.2
Requires-Dist: httpx>=0.28
Requires-Dist: mcp>=1.0
Requires-Dist: pyyaml>=6.0.3
Requires-Dist: rich>=13.0
Description-Content-Type: text/markdown

# NUCL

Minimal ML experiment platform. 2,000 lines of code.

NUCL wraps Azure ML, Vertex AI, and Vercel Sandbox behind a unified CLI and web dashboard. No servers to manage, no databases to maintain, no collectors to deploy. Every feature delegates to a managed service.

```
nucl run --name "vision/resnet-50-v2" --script train.py --gpu-type t4
nucl ps vision/
nucl log vision/resnet-50-v2 -f
nucl pull vision/resnet-50-v2
```

## Architecture

```mermaid
graph LR
    subgraph Clients
        CLI["CLI (Python)"]
        Web["Web Dashboard"]
    end

    subgraph Vercel
        API["Next.js API Routes"]
        Auth["Clerk (auth)"]
        DB["Drizzle + Neon"]
    end

    subgraph Sandbox["Vercel Sandbox (Python 3.13)"]
        AzureSDK["azure-ai-ml SDK"]
        VertexSDK["vertex AI SDK"]
    end

    subgraph Platforms
        AzureML["Azure ML"]
        VertexAI["Vertex AI"]
        SandboxRun["Sandbox (CPU)"]
    end

    CLI -- HTTP --> API
    Web -- HTTP --> API
    API --> Auth
    API --> DB
    API -- "job submission" --> Sandbox
    API -. "read ops (list, logs, cancel)" .-> Platforms
    AzureSDK --> AzureML
    VertexSDK --> VertexAI
    Sandbox --> SandboxRun
```

**Job submission** spins up a short-lived Vercel Sandbox with Python 3.13 and uses the official cloud SDKs to upload code and create training jobs. Read operations (list, logs, cancel) use direct REST API calls.

**Three platforms:**

| Platform | GPU | Use case |
|----------|-----|----------|
| Azure ML | Yes | Production training on Azure |
| Vertex AI | Yes | Production training on GCP |
| Sandbox | No (CPU) | Quick tests, no cloud account needed |

## Setup

### Web (Vercel)

```bash
cd web
bun install
cp .env.example .env.local  # fill in values
bun dev
```

Required environment variables:

```
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_...
CLERK_SECRET_KEY=sk_...
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
DATABASE_URL=postgresql://...
ENCRYPTION_KEY=<openssl rand -hex 32>
VERCEL_TOKEN=...
```

### CLI

```bash
cd cli
uv sync
uv run nucl --help
```

Or install globally:

```bash
uv tool install .
nucl --help
```

## CLI Commands

### Auth

```bash
nucl auth login                    # Browser-based sign-in
nucl auth logout
nucl auth status
```

### Teams (Clerk Organizations)

```bash
nucl team show                     # Current team info
nucl team set <org-id>             # Switch team
nucl team config azure             # Set Azure credentials for team
nucl team config vertex            # Set Vertex credentials for team
```

### Jobs

```bash
nucl run --name "project/experiment" --script train.py --gpu-type t4
nucl ps                            # List all experiments
nucl ps project/                   # Filter by folder
nucl log <job-id> -f               # Stream logs
nucl stop <job-id>
nucl pull <job-id> ./outputs       # Download results
```

### Models

```bash
nucl model ls
nucl model pull <name>
```

### HPO

```bash
nucl hpo run config.yaml
```

## Experiment Organization

Experiments use path-based naming with `/` as the folder separator:

```
lung-cancer/detection/yolov9-baseline
lung-cancer/detection/yolov9-augmented
lung-cancer/segmentation/unet-v1
breast-cancer/screening/resnet-50
```

Filter by prefix with `nucl ps lung-cancer/detection/`. The web dashboard renders folder paths with a muted prefix and bold experiment name.

## Cloud Credentials

Credentials are stored per-team using Clerk Organization `privateMetadata`, encrypted with AES-256-GCM. They never touch the CLI or browser -- only the server-side API routes decrypt them to submit jobs.

An org admin configures credentials once via the Team Settings page or `nucl team config`. All team members use them.

## In-Job Logging

NUCL does not ship a custom SDK. Use MLflow directly in your training scripts:

```python
import mlflow

mlflow.log_param("learning_rate", 0.001)
mlflow.log_metric("accuracy", 0.95)
mlflow.log_artifact("model.pth")
```

Both Azure ML and Vertex AI natively support MLflow.

## Tech Stack

| Layer | Technology |
|-------|------------|
| CLI | Python 3.11+, Click, httpx |
| Web | Next.js 16, React 19, TypeScript 6 |
| UI | shadcn, Tailwind CSS 4, TanStack Table |
| Data fetching | TanStack Query 5 |
| Auth | Clerk 7 (Organizations) |
| Database | Neon (serverless Postgres), Drizzle ORM |
| Job submission | Vercel Sandbox (Python 3.13) |
| Encryption | AES-256-GCM |
| Package management | uv (Python), Bun (JS) |

## Tests

```bash
# Web (163 tests)
cd web && bunx vitest run

# CLI (77 tests)
cd cli && uv run pytest -v

# Coverage
cd web && bunx vitest run --coverage    # 100% statements, 97.7% branches
cd cli && uv run pytest --cov=nucl      # 100% lines
```

## What NUCL Does Not Do

NUCL delegates everything it can. It does not:

- Provision VMs (cloud platforms do this)
- Collect logs (cloud platforms do this)
- Manage GPU quotas (cloud platforms do this)
- Handle preemption (cloud platforms do this)
- Build Docker images (use platform environments)
- Provide an in-job SDK (use MLflow)
- Run a backend server (Vercel handles this)
- Manage a database server (Neon handles this)

## License

Internal use only.
