Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .agents/skills
1 change: 1 addition & 0 deletions .claude/skills
1 change: 1 addition & 0 deletions .github/copilot-instructions.md
1 change: 1 addition & 0 deletions .github/skills
16 changes: 14 additions & 2 deletions .github/workflows/build-docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ jobs:
--config p/javascript \
--config p/react \
--config p/owasp-top-ten \
--exclude-rule=dockerfile.security.missing-user.missing-user
--exclude-rule=dockerfile.security.missing-user.missing-user \
--exclude-rule=yaml.github-actions.security.github-actions-mutable-action-tag.github-actions-mutable-action-tag

job-developer:
name: "labnow-open-dev"
Expand Down Expand Up @@ -86,10 +87,21 @@ jobs:
--build-arg "PROFILE_LOCALIZE=default" --build-arg "BASE_IMG=openclaw:latest"
push_image labnow-open-openclaw

job-hermes:
name: "labnow-open-hermes"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- run: |
source ./tool/tool.sh
build_image labnow-open-hermes latest ./src/labnow-open.Dockerfile \
--build-arg "PROFILE_LOCALIZE=default" --build-arg "BASE_IMG=hermes:latest"
push_image labnow-open-hermes


## Sync all images in this build (listed by "names") to mirror registry.
job-sync-images:
needs: ["job-developer", "job-data-science", "job-openclaw"]
needs: ["job-developer", "job-data-science", "job-openclaw", "job-hermes"]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,6 @@ dmypy.json

# Yarn cache
.yarn/

# Local project documentation
doc/dev/
Empty file added AGENTS.md
Empty file.
1 change: 1 addition & 0 deletions CLAUDE.md
52 changes: 42 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,47 @@
[![Visit Images on Quay.io](https://img.shields.io/badge/Quay.io-Images-green)](https://quay.io/organization/labnow)
[![Visit Images on DockerHub](https://img.shields.io/badge/DockerHub-Images-green)](https://hub.docker.com/u/LabNow)

Please generously STAR our project or donate to us!
Please generously STAR⭐️ our project or donate to us!
[![GitHub Stars](https://img.shields.io/github/stars/LabNow-ai/labnow-open.svg?label=Stars)](https://github.com/LabNow-ai/labnow-open/stargazers)

Discussion and contributions are welcome:
[![Join Discord Chat](https://img.shields.io/badge/Discuss_on-Discord-green)](https://discord.gg/kHUzgQxgbJ)
[![Open an Issue on GitHub](https://img.shields.io/github/issues/LabNow-ai/labnow-open)](https://github.com/LabNow-ai/labnow-open/issues)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/LabNow-ai/labnow-open)

> 中文文档:[doc/README-cn.md](doc/README-cn.md)

---

`LabNow Open` 是一个开源的容器化 AI/Data 工作空间项目,目标是让你用尽可能少的环境配置,快速得到可用的研发环境与工具门户。
LabNow Open is an open-source, containerized AI/data science workspace. It bundles a lightweight **Web Console** that lets you manage and launch common data science services — all from a single browser tab, with minimal setup.

## What's Included

- **JupyterLab** — interactive notebooks and data exploration
- **VS Code** (code-server) — full-featured code editor in the browser
- **RStudio Server** — R development environment
- **Shiny Server** — interactive R web applications
- **Hermes** — gateway and dashboard for AI tool orchestration
- **OpenClaw** — AI agent platform

All services run behind a unified **Caddy** reverse proxy on port 80, managed by **supervisord** for process lifecycle control.

## Image Variants

All variants are built from a single [Dockerfile](src/labnow-open.Dockerfile) and differ only in which base image they layer on top of:

项目内置了一个轻量 Web Console,用于管理和跳转常用数据科学服务,包含:
| Image Tag | Base Image | What It Contains |
|---|---|---|
| `labnow-open-dev` | `developer:latest` | Minimal dev tools + Web Console |
| `labnow-open-data-science` | `data-science-dev:latest` | Full data science stack (Python, R, Jupyter) |
| `labnow-open-hermes` | `hermes:latest` | Hermes gateway + dashboard |
| `labnow-open-openclaw` | `openclaw:latest` | OpenClaw AI agent platform |

- JupyterLab
- VS Code (code-server)
- RStudio Server
- Shiny Server
Images are published on both [Quay.io](https://quay.io/organization/labnow) and [Docker Hub](https://hub.docker.com/u/LabNow).

## 快速开始(直接使用现成镜像)
## Quick Start

如果你只想快速体验,建议直接运行镜像:
Run the full data science variant with a single command:

```bash
docker run --rm -it \
Expand All @@ -36,4 +55,17 @@ docker run --rm -it \
quay.io/labnow/labnow-open-data-science:latest
```

启动后访问:`http://localhost:8888/`
Then open **http://localhost:8888/** in your browser. The Web Console will show all available services — click any card to launch it.

### Other Variants

```bash
# Minimal developer image
docker run --rm -it -p 8888:80 quay.io/labnow/labnow-open-dev:latest

# With Hermes gateway
docker run --rm -it -p 8888:80 quay.io/labnow/labnow-open-hermes:latest

# With OpenClaw agent platform
docker run --rm -it -p 8888:80 quay.io/labnow/labnow-open-openclaw:latest
```
76 changes: 76 additions & 0 deletions doc/README-cn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
# LabNow Open

[![License](https://img.shields.io/badge/License-BSD%203--Clause-green.svg)](https://opensource.org/licenses/BSD-3-Clause)
[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/LabNow-ai/labnow-open/build-docker.yml?branch=main)](https://github.com/LabNow-ai/labnow-open/actions)
[![GitHub Stars](https://img.shields.io/github/stars/LabNow-ai/labnow-open.svg?label=Stars)](https://github.com/LabNow-ai/labnow-open/stargazers)

> English docs: [README.md](../README.md)

---

`LabNow Open` 是一个开源的容器化 AI/数据科学工作空间项目。目标是让你用尽可能少的环境配置,快速得到可用的研发环境与统一工具门户。

项目内置一个轻量 **Web Console**(React SPA),通过卡片式界面管理和跳转常用数据科学服务。所有服务由 **Caddy** 统一反向代理,由 **supervisord** 负责进程生命周期管理。

## 集成的服务

| 服务 | 说明 | Web 路径 |
|---|---|---|
| **JupyterLab** | 交互式 Notebook 与数据探索 | `/lab/` |
| **VS Code** (code-server) | 浏览器中的完整代码编辑器 | `/vscode/` |
| **RStudio Server** | R 语言开发环境 | `/rserver/` |
| **Shiny Server** | R Shiny 交互式 Web 应用 | `/rshiny/` |
| **Hermes** | AI 工具网关与仪表盘 | `/hermes/` |
| **OpenClaw** | AI Agent 平台 | `/openclaw/` |


## 镜像变体

所有变体由同一个 [Dockerfile](../src/labnow-open.Dockerfile) 构建,区别仅在于所基于的基础镜像不同:

| 镜像标签 | 基础镜像 | 包含内容 |
|---|---|---|
| `labnow-open-dev` | `developer:latest` | 精简开发工具 + Web Console |
| `labnow-open-data-science` | `data-science-dev:latest` | 完整数据科学栈(Python, R, Jupyter) |
| `labnow-open-hermes` | `hermes:latest` | Hermes 网关 + 仪表盘 |
| `labnow-open-openclaw` | `openclaw:latest` | OpenClaw AI Agent 平台 |

镜像发布在 [Quay.io](https://quay.io/organization/labnow) 和 [Docker Hub](https://hub.docker.com/u/LabNow)。

## 快速开始

一条命令启动完整数据科学环境:

```bash
docker run --rm -it \
--name labnow-open \
-p 8888:80 \
quay.io/labnow/labnow-open-data-science:latest
```

浏览器访问 **http://localhost:8888/**,Web Console 会列出所有可用服务,点击卡片即可启动。

### 其他变体

```bash
# 精简开发者镜像
docker run --rm -it -p 8888:80 quay.io/labnow/labnow-open-dev:latest

# 带 Hermes 网关
docker run --rm -it -p 8888:80 quay.io/labnow/labnow-open-hermes:latest

# 带 OpenClaw Agent 平台
docker run --rm -it -p 8888:80 quay.io/labnow/labnow-open-openclaw:latest
```


## 开发与 CI/CD

详细的本地开发指南与 CI/CD 流程说明见:[doc/README-dev.md](README-dev.md)

## 参与贡献

欢迎提交 Issue 和 Pull Request,也可以通过以下方式参与讨论:

- [![Join Discord Chat](https://img.shields.io/badge/Discuss_on-Discord-green)](https://discord.gg/kHUzgQxgbJ)
- [![Open an Issue](https://img.shields.io/github/issues/LabNow-ai/labnow-open)](https://github.com/LabNow-ai/labnow-open/issues)
130 changes: 113 additions & 17 deletions doc/README-dev.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,76 @@
# Develop with the `labnow/developer` image
# Development Guide

## Step 1: Start the developemnt environment
## Architecture

Start the development container and enter into the container.
```
Browser (:80)
v
┌──────────────────────────────────────────────┐
│ Caddy (reverse proxy) │
│ Serves static Console UI + routes traffic │
│ /home/* → supervisord RPC (:9001) │
│ /lab/* → JupyterLab (:8888) │
│ /vscode/* → code-server (:9999) │
│ /rserver/* → RStudio Server (:8787) │
│ /rshiny/* → Shiny Server (:3838) │
│ /hermes/* → Hermes Dashboard (:9119) │
│ /openclaw/* → OpenClaw (:18789) │
└──────────────────────────────────────────────┘
v
┌──────────────────────────────────────────────┐
│ supervisord (process manager) │
│ Auto-detects available tools and manages │
│ their start/stop/restart lifecycle │
└──────────────────────────────────────────────┘
v
┌──────────────────────────────────────────────┐
│ React SPA (Web Console) │
│ Carbon Design System, Vite 8, React 19 │
│ Card-based UI for service management │
└──────────────────────────────────────────────┘
```

## Project Structure

```
labnow-open/
├── src/
│ ├── labnow-open.Dockerfile # Multi-stage build (builder + runtime)
│ ├── labnow-open-web/ # React 19 + Vite + Carbon Design System
│ │ ├── src/App.jsx # Console UI with service card grid
│ │ ├── src/api/ # supervisord REST API client
│ │ ├── src/hooks/ # React hooks for state management
│ │ └── public/ # Static assets and logos
│ └── labnow-open-etc/ # Runtime configuration
│ ├── supervisord.conf # Process manager configuration
│ ├── Caddyfile # Reverse proxy routes
│ └── CaddyRoutes/ # Per-service route snippets
├── tool/
│ ├── tool.sh # CI helper: build/push Docker images
│ └── cicd/ # Dev & staging Docker Compose files
└── .github/workflows/
└── build-docker.yml # CI/CD: semgrep SAST, multi-variant builds
```

## Getting Started

### Method 1: Using run-dev.sh (Recommended)

Start the development container and enter into it:

```bash
# method 1:
./tool/cicd/run-dev.sh up
./tool/cicd/run-dev.sh enter
```

# method 2:
### Method 2: Manual Docker Run

```bash
docker run -d \
--name dev-labnow-open \
--container-name=dev-labnow-open \
-p 8888:80 -p 3000:3000 \
-v $(pwd):/root/ \
quay.io/labnow/data-science-dev \
Expand All @@ -21,28 +79,66 @@ docker run -d \
docker exec -it dev-labnow-open bash
```

## Step 2: Update configs and start the supervisord
## Running the App in Dev Mode

```bash
mkdir -pv /etc/supervisord && ln -sf /root/src/labnow-open-etc/supervisord.conf /etc/supervisord/
mkdir -pv /etc/caddy && ln -sf /root/src/labnow-open-etc/Caddyfile /etc/caddy/
Inside the container, link configs and start services:

```bash
mkdir -pv /etc/supervisord && ln -sf /root/src/labnow-open-etc/supervisord.conf /etc/supervisord/
mkdir -pv /etc/caddy && ln -sf /root/src/labnow-open-etc/Caddyfile /etc/caddy/
export STATIC_DIR=/root/src/labnow-open-web/dist && start-supervisord.sh
```

## Step 3: Access the service from the browser
Then access: **http://localhost:8888/**

http://localhost:8888/
## Standalone Frontend Development

## Step 4: Build the image and run the built image
Develop the React frontend independently (without Docker):

```bash
docker build -t quay.io/labnow-dev/labnow-open-dev:latest \
-f src/labnow-open.Dockerfile \
--build-arg PROFILE_LOCALIZE=aliyun-pub .
cd src/labnow-open-web
pnpm install
pnpm run dev # Dev server on http://localhost:3000
pnpm run build # Production build to dist/
```

In dev mode, Vite proxies `/api` requests to `localhost:80`, so you can run the frontend standalone against a running backend.

## Building Docker Images Locally

```bash
docker build -t labnow-open-dev:latest \
-f src/labnow-open.Dockerfile \
--build-arg PROFILE_LOCALIZE=aliyun-pub .
```

Run the built image:

```bash
docker run --rm -it \
--name dev-labnow-open \
-p 8080:80 \
quay.io/labnow-dev/labnow-open-dev:latest
labnow-open-dev:latest
```

## CI/CD

On push to `main`, pull requests, tag releases (`v*`), and weekly schedules, GitHub Actions:

1. Runs **semgrep SAST** (static analysis security testing)
2. Builds all four image variants in parallel
3. Pushes to `quay.io/labnow/` and `docker.io/labnow/`
4. Optionally syncs to a mirror registry

See [.github/workflows/build-docker.yml](../.github/workflows/build-docker.yml) for details.

### Image Variants

All variants are built from a single [Dockerfile](../src/labnow-open.Dockerfile) and differ only in which base image they layer on top of:

| Image Tag | Base Image | What It Contains |
|---|---|---|
| `labnow-open-dev` | `developer:latest` | Minimal dev tools + Web Console |
| `labnow-open-data-science` | `data-science-dev:latest` | Full data science stack (Python, R, Jupyter) |
| `labnow-open-hermes` | `hermes:latest` | Hermes gateway + dashboard |
| `labnow-open-openclaw` | `openclaw:latest` | OpenClaw AI agent platform |
15 changes: 15 additions & 0 deletions src/labnow-open-etc/CaddyRoutes/hermes.caddy
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Hermes
@path_user_hermes_no_slash path {$URL_PREFIX:}hermes
redir @path_user_hermes_no_slash {path}/ 308

@path_user_hermes path {$URL_PREFIX:}hermes/*
handle @path_user_hermes {
uri strip_prefix {$URL_PREFIX:}hermes
reverse_proxy localhost:9119
}

@path_user_hermes_readiness path {$URL_PREFIX:/}api
handle @path_user_hermes_readiness {
rewrite * /api/status
reverse_proxy 127.0.0.1:9119
}
13 changes: 13 additions & 0 deletions src/labnow-open-etc/CaddyRoutes/openclaw.caddy
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# OpenClaw
# Redirect non-WebSocket requests to the canonical trailing-slash URL
@path_user_openclaw_no_slash {
path {$URL_PREFIX:}openclaw
not header Connection *Upgrade*
}
redir @path_user_openclaw_no_slash {path}/ 308

@path_user_openclaw path {$URL_PREFIX:}openclaw/*
handle @path_user_openclaw {
uri strip_prefix {$URL_PREFIX:}openclaw
reverse_proxy localhost:18789
}
Loading