From 2a05914150a2121b4bbe6638444971624eb7a856 Mon Sep 17 00:00:00 2001
From: jinliyl <6469360+jinliyl@users.noreply.github.com>
Date: Thu, 13 Aug 2026 11:07:37 +0800
Subject: [PATCH] feat: distribute Studio as an optional package (#454)
---
.github/workflows/pre-commit.yml | 2 +-
.github/workflows/python-publish.yml | 25 ++-
.github/workflows/unittest.yml | 2 +-
.github/workflows/windows-smoke.yml | 2 +-
README.md | 9 +-
docs/en/contributing.md | 2 +-
docs/en/framework.md | 8 +-
docs/en/quick_start.md | 5 +-
docs/zh/contributing.md | 2 +-
docs/zh/framework.md | 5 +-
docs/zh/quick_start.md | 5 +-
packages/reme_ai_studio/README.md | 203 ++++++++++++++++++
packages/reme_ai_studio/pyproject.toml | 24 +++
.../src/reme_ai_studio/__init__.py | 11 +
.../src/reme_ai_studio/static/.gitignore | 2 +
pyproject.toml | 5 +-
reme/utils/web_static.py | 23 +-
scripts/package_studio.py | 58 +++++
tests/unit/test_http_web_workspace.py | 13 +-
tests/unit/test_package_versions.py | 28 +++
website/README.md | 13 +-
website/README_ZH.md | 13 +-
22 files changed, 426 insertions(+), 34 deletions(-)
create mode 100644 packages/reme_ai_studio/README.md
create mode 100644 packages/reme_ai_studio/pyproject.toml
create mode 100644 packages/reme_ai_studio/src/reme_ai_studio/__init__.py
create mode 100644 packages/reme_ai_studio/src/reme_ai_studio/static/.gitignore
create mode 100644 scripts/package_studio.py
create mode 100644 tests/unit/test_package_versions.py
diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml
index 7444fe65..191cbb95 100644
--- a/.github/workflows/pre-commit.yml
+++ b/.github/workflows/pre-commit.yml
@@ -23,7 +23,7 @@ jobs:
pip install -U setuptools wheel
- name: Install
run: |
- pip install -q -e ".[dev,core]"
+ pip install -q -e packages/reme_ai_studio -e ".[dev,core]"
- name: Install pre-commit
run: |
pre-commit install
diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml
index 82a80a4a..8bb12ca7 100644
--- a/.github/workflows/python-publish.yml
+++ b/.github/workflows/python-publish.yml
@@ -29,30 +29,33 @@ jobs:
node-version: '22'
cache: npm
cache-dependency-path: website/package-lock.json
+ - name: Set up Python
+ uses: actions/setup-python@v6
+ with:
+ python-version: '3.11'
- name: Build web workspace
working-directory: website
run: |
npm ci
npm run build:static
- rm -rf ../reme/web
- mkdir -p ../reme/web
- cp -R dist-static/. ../reme/web/
- - name: Set up Python
- uses: actions/setup-python@v6
- with:
- python-version: '3.11'
+ - name: Prepare Studio package
+ run: python scripts/package_studio.py
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install setuptools wheel build
- name: Build package
- run: python -m build
+ run: |
+ python -m build --outdir dist
+ python -m build packages/reme_ai_studio --outdir dist
- name: Test installation
run: |
- WHEEL="$(ls dist/*.whl)"
- pip install "${WHEEL}[core]"
+ REME_WHEEL="$(pwd)/$(ls dist/reme_ai-[0-9]*.whl)"
+ python -m zipfile -l "${REME_WHEEL}" | (! grep 'reme/web/')
+ pip install --find-links "$(pwd)/dist" "${REME_WHEEL}[core]"
python -c "import reme; print(reme.__version__)"
- python -c "from importlib.resources import files; assert (files('reme') / 'web' / 'index.html').is_file()"
+ python -c "from reme_ai_studio import static_dir; assert (static_dir() / 'index.html').is_file()"
+ python -c "from reme.utils import resolve_web_static_dir; assert (resolve_web_static_dir() / 'index.html').is_file()"
- name: Publish package to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
diff --git a/.github/workflows/unittest.yml b/.github/workflows/unittest.yml
index 0eb9e664..4fd5886e 100644
--- a/.github/workflows/unittest.yml
+++ b/.github/workflows/unittest.yml
@@ -32,7 +32,7 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --upgrade pip setuptools wheel
- pip install -e ".[dev,core]"
+ pip install -e packages/reme_ai_studio -e ".[dev,core]"
pip install coverage
- name: Run unit tests
diff --git a/.github/workflows/windows-smoke.yml b/.github/workflows/windows-smoke.yml
index 8a1f787a..e72080a1 100644
--- a/.github/workflows/windows-smoke.yml
+++ b/.github/workflows/windows-smoke.yml
@@ -32,7 +32,7 @@ jobs:
- name: Install package
run: |
python -m pip install --upgrade pip setuptools wheel
- pip install -e ".[dev,core]"
+ pip install -e packages/reme_ai_studio -e ".[dev,core]"
- name: Run version job
run: reme start service.backend=cli job=version
diff --git a/README.md b/README.md
index a1449025..26e26741 100644
--- a/README.md
+++ b/README.md
@@ -86,12 +86,16 @@ Install from pip:
pip install "reme-ai[core]"
```
+The base `reme-ai` package contains only the Python service and library. ReMe Studio is distributed separately and is
+installed by the `web` and `core` extras. Use `pip install reme-ai` for embedded or headless integrations that do not
+need the frontend, or `pip install "reme-ai[web]"` when Studio is needed without the other `core` integrations.
+
Install from source:
```bash
git clone https://github.com/agentscope-ai/ReMe.git
cd ReMe
-pip install -e ".[core]"
+pip install -e packages/reme_ai_studio -e ".[core]"
```
### Environment Variables
@@ -134,7 +138,8 @@ reme start service.port=8181
After startup, check the service status. If you use a custom port, replace `2333` in the URL below with that port.
-When the web build is available, the HTTP service also serves **ReMe Studio** at . Studio can
+When the `web` or `core` extra is installed, the HTTP service also serves **ReMe Studio** at
+. Studio can
browse, edit, and search the workspace, chat with the read-only workspace agent, and inspect the digest wikilink graph.
Set `service.web_enabled=false` to disable it, or use `service.web_static_dir` / `REME_WEB_STATIC_DIR` to provide a
custom static build. The Job API remains available when no web build is found.
diff --git a/docs/en/contributing.md b/docs/en/contributing.md
index 8671c292..44c8be25 100644
--- a/docs/en/contributing.md
+++ b/docs/en/contributing.md
@@ -39,7 +39,7 @@ The project requires Python 3.11 or later. A virtual environment is recommended:
```bash
python -m venv .venv
source .venv/bin/activate
-pip install -e ".[dev,full]"
+pip install -e packages/reme_ai_studio -e ".[dev,full]"
pre-commit install
```
diff --git a/docs/en/framework.md b/docs/en/framework.md
index 5774e734..d95cab1d 100644
--- a/docs/en/framework.md
+++ b/docs/en/framework.md
@@ -166,10 +166,10 @@ HTTP service behavior:
| `enable_serve: false` | No endpoint is registered. |
After registering Job endpoints, the HTTP service can also mount the ReMe Studio single-page application. The default is
-`service.web_enabled=true`. Builds are resolved from `service.web_static_dir`, `REME_WEB_STATIC_DIR`, packaged
-`reme/web`, and source-tree locations such as `website/dist-static`. If no `index.html` is found, only the frontend is
-skipped and the Job API remains available. The Studio `GET` fallback does not replace existing `POST /`
-routes.
+`service.web_enabled=true`. Builds are resolved from `service.web_static_dir`, `REME_WEB_STATIC_DIR`, the optional
+`reme-ai-studio` package installed by the `web` and `core` extras, and source-tree locations such as
+`website/dist-static`. If no `index.html` is found, only the frontend is skipped and the Job API remains available. The
+Studio `GET` fallback does not replace existing `POST /` routes.
MCP service behavior:
diff --git a/docs/en/quick_start.md b/docs/en/quick_start.md
index 2bc7a806..d2791d89 100644
--- a/docs/en/quick_start.md
+++ b/docs/en/quick_start.md
@@ -15,7 +15,7 @@ Install from source:
```bash
git clone https://github.com/agentscope-ai/ReMe.git
cd ReMe
-pip install -e ".[core]"
+pip install -e packages/reme_ai_studio -e ".[core]"
```
Installing the `core` extra is recommended. The current code imports the AgentScope wrapper, and self-evolving memory
@@ -56,7 +56,8 @@ reme help
`reme help` lists server actions. Ordinary commands invoke server Jobs over HTTP.
-When the package includes the web build, open for ReMe Studio. It uses the same service to
+The base `reme-ai` package does not include frontend assets. Install `reme-ai[web]` or `reme-ai[core]`, then open
+ for ReMe Studio. It uses the same service to
browse, edit, and search the workspace and inspect the digest wikilink graph. Disable it with
`service.web_enabled=false`, or provide a custom build with `service.web_static_dir` / `REME_WEB_STATIC_DIR`. The Job
API still starts if no web build is found.
diff --git a/docs/zh/contributing.md b/docs/zh/contributing.md
index 495db1f0..0e134e66 100644
--- a/docs/zh/contributing.md
+++ b/docs/zh/contributing.md
@@ -37,7 +37,7 @@ ReMe 的核心代码位于:
```bash
python -m venv .venv
source .venv/bin/activate
-pip install -e ".[dev,full]"
+pip install -e packages/reme_ai_studio -e ".[dev,full]"
pre-commit install
```
diff --git a/docs/zh/framework.md b/docs/zh/framework.md
index 7052f05e..6c17612d 100644
--- a/docs/zh/framework.md
+++ b/docs/zh/framework.md
@@ -161,8 +161,9 @@ HTTP service 行为:
| `enable_serve: false` | 不注册 endpoint |
HTTP service 还可以在所有 Job endpoint 注册完成后挂载 ReMe Studio 单页应用。默认 `service.web_enabled=true`;构建产物按
-`service.web_static_dir`、`REME_WEB_STATIC_DIR`、包内 `reme/web` 和源码树 `website/dist-static` 等候选位置解析。找不到
-`index.html` 时只跳过前端,Job API 仍然可用。Studio 的 `GET` fallback 不会覆盖已有的 `POST /`。
+`service.web_static_dir`、`REME_WEB_STATIC_DIR`、由 `web` 或 `core` extra 安装的可选 `reme-ai-studio` 包,以及源码树
+`website/dist-static` 等候选位置解析。找不到 `index.html` 时只跳过前端,Job API 仍然可用。Studio 的 `GET` fallback 不会覆盖
+已有的 `POST /`。
MCP service 行为:
diff --git a/docs/zh/quick_start.md b/docs/zh/quick_start.md
index afa0d5ef..e00688e1 100644
--- a/docs/zh/quick_start.md
+++ b/docs/zh/quick_start.md
@@ -15,7 +15,7 @@ pip install "reme-ai[core]"
```bash
git clone https://github.com/agentscope-ai/ReMe.git
cd ReMe
-pip install -e ".[core]"
+pip install -e packages/reme_ai_studio -e ".[core]"
```
`core` extra 建议安装:当前代码会导入 AgentScope wrapper,自进化记忆也依赖它。
@@ -55,7 +55,8 @@ reme help
`reme help` 会列出服务端 action。普通命令会通过 HTTP 调用服务端 Job。
-如果安装包中包含 Web 构建产物,浏览器打开 即可进入 ReMe Studio,在同一服务中浏览、编辑和搜索
+基础 `reme-ai` 包不包含前端资源。安装 `reme-ai[web]` 或 `reme-ai[core]` 后,浏览器打开
+ 即可进入 ReMe Studio,在同一服务中浏览、编辑和搜索
workspace,并查看 digest Wikilink 图。可用 `service.web_enabled=false` 关闭,或通过 `service.web_static_dir` /
`REME_WEB_STATIC_DIR`
指定自定义静态目录;找不到构建产物时,Job API 仍会正常启动。
diff --git a/packages/reme_ai_studio/README.md b/packages/reme_ai_studio/README.md
new file mode 100644
index 00000000..bda397ca
--- /dev/null
+++ b/packages/reme_ai_studio/README.md
@@ -0,0 +1,203 @@
+# ReMe Studio
+
+English | [简体中文](#简体中文)
+
+ReMe Studio is the local web workspace for ReMe. It lets you browse and edit user-owned workspace files, explore memory
+links, and chat with the ReMe Agent without moving durable memory into a separate application database. Search indexes,
+graphs, and other derived metadata remain rebuildable from the source files.
+
+
+
+## Installation
+
+Install Studio together with ReMe's optional integrations:
+
+```bash
+pip install "reme-ai[core]"
+```
+
+For Studio without the other optional integrations, use `pip install "reme-ai[web]"`. The base `reme-ai` package is
+headless and does not include the frontend assets.
+
+## Features
+
+- **Workspace browsing**: browse the full workspace or focus on journal and knowledge files through dedicated views. The
+ navigator refreshes as files change on disk.
+- **Markdown editing and preview**: open multiple files in tabs, render Markdown front matter and GitHub Flavored
+ Markdown, edit with Monaco, save with optimistic modification-time checks, and download files locally.
+- **Memory graph**: inspect indexed wikilinks under the `wiki`, `personal`, and
+ `procedure` knowledge roots, follow inbound and outbound links, and open the corresponding Markdown source.
+- **Agent chat**: stream conversations with the read-only workspace Agent, see tool calls and token usage, and drag
+ workspace files into the conversation as references.
+- **Service management**: inspect service and component memory usage, review the effective redacted configuration and
+ version, and rebuild derived indexes without modifying source memory files.
+- **Personalization**: switch between English and Chinese, and use light, dark, or system appearance.
+
+## Requirements
+
+- Python 3.11 or newer with ReMe installed.
+- A running ReMe HTTP service. Agent chat additionally requires a working Agent and model configuration.
+- Node.js 22.13 or newer is required only when developing or building Studio from source.
+
+See the [repository README](https://github.com/agentscope-ai/ReMe#readme) for ReMe installation and backend configuration.
+
+## Development
+
+Start ReMe from the repository root, then run the frontend in another terminal:
+
+```bash
+# Terminal 1, from the repository root
+reme start
+
+# Terminal 2
+cd website
+npm install
+npm run dev
+```
+
+Open . The frontend connects to
+`http://127.0.0.1:2333` by default. Override it when needed:
+
+```bash
+NEXT_PUBLIC_REME_API_URL=http://127.0.0.1:8000 npm run dev
+```
+
+## ReMe-hosted static build
+
+ReMe can serve Studio from the same FastAPI process as its HTTP API. Build the static variant and restart ReMe:
+
+```bash
+cd website
+npm ci
+npm run build:static
+cd ..
+reme start
+```
+
+Open . The static build uses same-origin requests by default. For standalone static development,
+run `npm run dev:static` and set
+`VITE_REME_API_URL` to the running ReMe service URL when necessary.
+
+The regular `npm run build` command remains the vinext/Sites deployment build;
+`npm run build:static` creates `dist-static/` exclusively for FastAPI and Python package distribution.
+
+## Configuration
+
+The workspace hides dotfiles and dot-directories. It displays only Markdown and text files by default. Configure the
+allowed extensions as a comma-separated list in `.env.local`:
+
+```bash
+NEXT_PUBLIC_REME_WORKSPACE_EXTENSIONS=md,txt,mdx
+```
+
+The memory graph requires an index built by ReMe. Rebuilding the index from the Studio settings regenerates derived data
+from workspace files and does not modify the source memory.
+
+## Checks
+
+```bash
+npm run format:check
+npm run lint
+npm run build
+npm run build:static
+npm test
+```
+
+---
+
+# 简体中文
+
+[English](#reme-studio) | 简体中文
+
+ReMe Studio 是 ReMe 的本地 Web 工作区。你可以在这里浏览和编辑自己拥有的工作区文件、探索记忆之间的联系,并与 ReMe Agent
+对话,而无需将持久记忆迁移到独立的应用数据库中。搜索索引、图谱和其他派生元数据均可根据源文件重建。
+
+
+
+## 安装
+
+安装 Studio 和 ReMe 的可选集成功能:
+
+```bash
+pip install "reme-ai[core]"
+```
+
+如果只需要 Studio,不需要其他可选集成,可以使用 `pip install "reme-ai[web]"`。基础 `reme-ai` 包以无界面模式分发,
+不包含前端资源。
+
+## 功能
+
+- **浏览工作区**:浏览完整工作区,或通过独立视图聚焦日记和知识文件;磁盘中的文件发生变化后,导航器会自动刷新。
+- **Markdown 编辑与预览**:在多个标签页中打开文件,渲染 Markdown front matter 和 GitHub Flavored Markdown,使用 Monaco
+ 编辑器编辑,通过修改时间检查安全保存,并可将文件下载到本地。
+- **记忆图谱**:查看知识库 `wiki`、`personal` 和 `procedure` 目录中已索引的 wikilink,检查入链和出链,并从图谱打开对应的
+ Markdown 源文件。
+- **Agent 对话**:与只读工作区 Agent 进行流式对话,查看工具调用和 token 用量,还可将工作区文件拖入对话作为引用。
+- **服务管理**:查看服务及组件的内存使用情况、当前生效的脱敏配置和版本,并在不修改记忆源文件的情况下重建派生索引。
+- **个性化设置**:切换中英文界面,并使用浅色、深色或跟随系统的外观。
+
+## 环境要求
+
+- Python 3.11 或更高版本,并已安装 ReMe。
+- 正在运行的 ReMe HTTP 服务。Agent 对话还需要可用的 Agent 和模型配置。
+- 只有从源码开发或构建 Studio 时才需要 Node.js 22.13 或更高版本。
+
+ReMe 的安装和后端配置请参阅[仓库中文 README](https://github.com/agentscope-ai/ReMe/blob/main/README_ZH.md)。
+
+## 本地开发
+
+先在仓库根目录启动 ReMe,然后在另一个终端运行前端:
+
+```bash
+# 终端 1:仓库根目录
+reme start
+
+# 终端 2
+cd website
+npm install
+npm run dev
+```
+
+打开 。前端默认连接 `http://127.0.0.1:2333`,需要时可覆盖该地址:
+
+```bash
+NEXT_PUBLIC_REME_API_URL=http://127.0.0.1:8000 npm run dev
+```
+
+## 由 ReMe 托管的静态构建
+
+ReMe 可以通过提供 HTTP API 的同一个 FastAPI 进程托管 Studio。构建静态版本并重启 ReMe:
+
+```bash
+cd website
+npm ci
+npm run build:static
+cd ..
+reme start
+```
+
+打开 。静态构建默认使用同源请求。进行独立的静态开发时,运行
+`npm run dev:static`;如有需要,将 `VITE_REME_API_URL` 设置为正在运行的 ReMe 服务地址。
+
+常规的 `npm run build` 命令仍用于 vinext/Sites 部署构建;`npm run build:static` 仅为 FastAPI 和 Python 包分发生成
+`dist-static/`。
+
+## 配置
+
+工作区会隐藏点文件和点目录,并且默认只显示 Markdown 和文本文件。可以在 `.env.local` 中通过逗号分隔的列表配置允许显示的扩展名:
+
+```bash
+NEXT_PUBLIC_REME_WORKSPACE_EXTENSIONS=md,txt,mdx
+```
+
+记忆图谱依赖 ReMe 构建的索引。在 Studio 设置中重建索引时,只会根据工作区文件重新生成派生数据,不会修改记忆源文件。
+
+## 检查
+
+```bash
+npm run format:check
+npm run lint
+npm run build
+npm run build:static
+npm test
+```
diff --git a/packages/reme_ai_studio/pyproject.toml b/packages/reme_ai_studio/pyproject.toml
new file mode 100644
index 00000000..8fe88424
--- /dev/null
+++ b/packages/reme_ai_studio/pyproject.toml
@@ -0,0 +1,24 @@
+[project]
+name = "reme-ai-studio"
+version = "0.4.1.6"
+description = "Optional ReMe Studio static frontend."
+readme = "README.md"
+license = "Apache-2.0"
+requires-python = ">=3.11"
+
+[project.urls]
+Homepage = "https://github.com/agentscope-ai/ReMe/tree/main/website"
+Documentation = "https://reme.agentscope.io"
+Repository = "https://github.com/agentscope-ai/ReMe"
+
+[tool.setuptools]
+package-dir = { "" = "src" }
+packages = ["reme_ai_studio"]
+include-package-data = false
+
+[tool.setuptools.package-data]
+"reme_ai_studio" = ["static/**"]
+
+[build-system]
+requires = ["setuptools>=45", "wheel"]
+build-backend = "setuptools.build_meta"
diff --git a/packages/reme_ai_studio/src/reme_ai_studio/__init__.py b/packages/reme_ai_studio/src/reme_ai_studio/__init__.py
new file mode 100644
index 00000000..41ae36df
--- /dev/null
+++ b/packages/reme_ai_studio/src/reme_ai_studio/__init__.py
@@ -0,0 +1,11 @@
+"""Static asset provider for the optional ReMe Studio frontend."""
+
+from pathlib import Path
+
+
+def static_dir() -> Path:
+ """Return the installed Studio static asset directory."""
+ return Path(__file__).resolve().parent / "static"
+
+
+__all__ = ["static_dir"]
diff --git a/packages/reme_ai_studio/src/reme_ai_studio/static/.gitignore b/packages/reme_ai_studio/src/reme_ai_studio/static/.gitignore
new file mode 100644
index 00000000..d6b7ef32
--- /dev/null
+++ b/packages/reme_ai_studio/src/reme_ai_studio/static/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/pyproject.toml b/pyproject.toml
index 364a6106..f2c24e0e 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -42,6 +42,9 @@ dependencies = [
]
[project.optional-dependencies]
+web = [
+ "reme-ai-studio==0.4.1.6",
+]
core = [
"agentscope==2.0.4.post1",
"claude-agent-sdk>=0.2.126",
@@ -55,6 +58,7 @@ core = [
"neo4j>=6.2.0",
"networkx>=3.4.2",
"polars>=1.43.0",
+ "reme-ai-studio==0.4.1.6",
]
dev = [
"pre-commit>=4.6.1",
@@ -80,7 +84,6 @@ include-package-data = true
[tool.setuptools.package-data]
"*" = ["py.typed", "**/*.yaml", "**/*.json"]
-"reme" = ["web/**"]
"reme.components.tokenizer" = ["stopwords"]
[tool.setuptools.dynamic]
diff --git a/reme/utils/web_static.py b/reme/utils/web_static.py
index 97d38a3e..aa58f4b4 100644
--- a/reme/utils/web_static.py
+++ b/reme/utils/web_static.py
@@ -8,20 +8,39 @@ from pathlib import Path
REME_WEB_STATIC_DIR = "REME_WEB_STATIC_DIR"
+def _packaged_studio_dir() -> Path | None:
+ """Return the static directory supplied by the optional Studio package."""
+ try:
+ from reme_ai_studio import static_dir
+ except ImportError:
+ return None
+ return static_dir()
+
+
def resolve_web_static_dir(configured_dir: str | None = None) -> Path | None:
"""Return the first directory containing a built workspace ``index.html``."""
package_dir = Path(__file__).resolve().parent.parent
repository_dir = package_dir.parent
cwd = Path.cwd()
- candidates = [
+ explicit_candidates = [
configured_dir,
os.getenv(REME_WEB_STATIC_DIR),
+ ]
+ for candidate in explicit_candidates:
+ if not candidate:
+ continue
+ path = Path(candidate).expanduser().resolve()
+ if path.is_dir() and (path / "index.html").is_file():
+ return path
+
+ fallback_candidates = [
+ _packaged_studio_dir(),
package_dir / "web",
repository_dir / "website" / "dist-static",
cwd / "website" / "dist-static",
cwd / "web_dist",
]
- for candidate in candidates:
+ for candidate in fallback_candidates:
if not candidate:
continue
path = Path(candidate).expanduser().resolve()
diff --git a/scripts/package_studio.py b/scripts/package_studio.py
new file mode 100644
index 00000000..66ed4ca5
--- /dev/null
+++ b/scripts/package_studio.py
@@ -0,0 +1,58 @@
+"""Prepare the optional ReMe Studio Python distribution."""
+
+from __future__ import annotations
+
+import argparse
+import shutil
+from pathlib import Path
+
+REPOSITORY_DIR = Path(__file__).resolve().parents[1]
+WEBSITE_DIR = REPOSITORY_DIR / "website"
+PACKAGE_DIR = REPOSITORY_DIR / "packages" / "reme_ai_studio"
+STATIC_DIR = PACKAGE_DIR / "src" / "reme_ai_studio" / "static"
+
+_RAW_WEBSITE_URL = "https://raw.githubusercontent.com/agentscope-ai/ReMe/main/website"
+_REPOSITORY_URL = "https://github.com/agentscope-ai/ReMe"
+
+
+def build_readme() -> str:
+ """Compose the PyPI description from the English and Chinese Studio docs."""
+ english = (WEBSITE_DIR / "README.md").read_text(encoding="utf-8")
+ chinese = (WEBSITE_DIR / "README_ZH.md").read_text(encoding="utf-8")
+ english = english.replace("English | [简体中文](./README_ZH.md)", "English | [简体中文](#简体中文)")
+ chinese = chinese.replace(
+ "# ReMe Studio\n\n[English](./README.md) | 简体中文",
+ "# 简体中文\n\n[English](#reme-studio) | 简体中文",
+ )
+ for relative, absolute in {
+ "./public/og.jpg": f"{_RAW_WEBSITE_URL}/public/og.jpg",
+ "../README.md": f"{_REPOSITORY_URL}#readme",
+ "../README_ZH.md": f"{_REPOSITORY_URL}/blob/main/README_ZH.md",
+ }.items():
+ english = english.replace(relative, absolute)
+ chinese = chinese.replace(relative, absolute)
+ return f"{english.rstrip()}\n\n---\n\n{chinese.rstrip()}\n"
+
+
+def prepare_package(*, copy_static: bool = True) -> None:
+ """Generate the PyPI README and optionally stage the static build."""
+ (PACKAGE_DIR / "README.md").write_text(build_readme(), encoding="utf-8")
+ if not copy_static:
+ return
+ source = WEBSITE_DIR / "dist-static"
+ if not (source / "index.html").is_file():
+ raise FileNotFoundError(f"Studio static build is unavailable: {source}")
+ shutil.rmtree(STATIC_DIR, ignore_errors=True)
+ shutil.copytree(source, STATIC_DIR)
+
+
+def main() -> None:
+ """Run the package preparation command."""
+ parser = argparse.ArgumentParser(description=__doc__)
+ parser.add_argument("--readme-only", action="store_true", help="Generate only the PyPI README")
+ args = parser.parse_args()
+ prepare_package(copy_static=not args.readme_only)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/tests/unit/test_http_web_workspace.py b/tests/unit/test_http_web_workspace.py
index 96472a5b..891f943a 100644
--- a/tests/unit/test_http_web_workspace.py
+++ b/tests/unit/test_http_web_workspace.py
@@ -1,7 +1,8 @@
"""HTTP service coverage for the optional bundled web workspace."""
+import sys
from pathlib import Path
-from types import SimpleNamespace
+from types import ModuleType, SimpleNamespace
import pytest
from fastapi.testclient import TestClient
@@ -100,3 +101,13 @@ def test_static_dir_configuration_precedes_environment(monkeypatch, tmp_path: Pa
assert resolve_web_static_dir(str(configured)) == configured.resolve()
assert resolve_web_static_dir() == environment.resolve()
+
+
+def test_static_dir_uses_optional_studio_package(monkeypatch, tmp_path: Path) -> None:
+ """Use static assets supplied by the separately installed Studio wheel."""
+ static_dir = _static_build(tmp_path / "studio")
+ studio = ModuleType("reme_ai_studio")
+ studio.static_dir = lambda: static_dir # type: ignore[attr-defined]
+ monkeypatch.setitem(sys.modules, "reme_ai_studio", studio)
+
+ assert resolve_web_static_dir() == static_dir.resolve()
diff --git a/tests/unit/test_package_versions.py b/tests/unit/test_package_versions.py
new file mode 100644
index 00000000..fb5b9b94
--- /dev/null
+++ b/tests/unit/test_package_versions.py
@@ -0,0 +1,28 @@
+"""Keep the separately published distributions version-compatible."""
+
+from pathlib import Path
+import tomllib
+
+import reme
+from scripts.package_studio import build_readme
+
+
+def test_studio_package_and_extra_versions_match_reme() -> None:
+ """Require one version bump to update both wheels and their exact pin."""
+ repository = Path(__file__).resolve().parents[2]
+ main_config = tomllib.loads((repository / "pyproject.toml").read_text(encoding="utf-8"))
+ studio_config = tomllib.loads(
+ (repository / "packages" / "reme_ai_studio" / "pyproject.toml").read_text(encoding="utf-8"),
+ )
+ expected_dependency = f"reme-ai-studio=={reme.__version__}"
+
+ assert studio_config["project"]["version"] == reme.__version__
+ assert main_config["project"]["optional-dependencies"]["web"] == [expected_dependency]
+ assert expected_dependency in main_config["project"]["optional-dependencies"]["core"]
+
+
+def test_studio_readme_is_generated_from_website_docs() -> None:
+ """Keep the packaged PyPI description synchronized with the source docs."""
+ repository = Path(__file__).resolve().parents[2]
+ packaged_readme = repository / "packages" / "reme_ai_studio" / "README.md"
+ assert packaged_readme.read_text(encoding="utf-8") == build_readme()
diff --git a/website/README.md b/website/README.md
index 28f52f9d..d8fda46f 100644
--- a/website/README.md
+++ b/website/README.md
@@ -8,6 +8,17 @@ graphs, and other derived metadata remain rebuildable from the source files.

+## Installation
+
+Install Studio together with ReMe's optional integrations:
+
+```bash
+pip install "reme-ai[core]"
+```
+
+For Studio without the other optional integrations, use `pip install "reme-ai[web]"`. The base `reme-ai` package is
+headless and does not include the frontend assets.
+
## Features
- **Workspace browsing**: browse the full workspace or focus on journal and knowledge files through dedicated views. The
@@ -24,9 +35,9 @@ graphs, and other derived metadata remain rebuildable from the source files.
## Requirements
-- Node.js 22.13 or newer.
- Python 3.11 or newer with ReMe installed.
- A running ReMe HTTP service. Agent chat additionally requires a working Agent and model configuration.
+- Node.js 22.13 or newer is required only when developing or building Studio from source.
See the [repository README](../README.md) for ReMe installation and backend configuration.
diff --git a/website/README_ZH.md b/website/README_ZH.md
index 75ec6054..c6f813ee 100644
--- a/website/README_ZH.md
+++ b/website/README_ZH.md
@@ -7,6 +7,17 @@ ReMe Studio 是 ReMe 的本地 Web 工作区。你可以在这里浏览和编辑

+## 安装
+
+安装 Studio 和 ReMe 的可选集成功能:
+
+```bash
+pip install "reme-ai[core]"
+```
+
+如果只需要 Studio,不需要其他可选集成,可以使用 `pip install "reme-ai[web]"`。基础 `reme-ai` 包以无界面模式分发,
+不包含前端资源。
+
## 功能
- **浏览工作区**:浏览完整工作区,或通过独立视图聚焦日记和知识文件;磁盘中的文件发生变化后,导航器会自动刷新。
@@ -20,9 +31,9 @@ ReMe Studio 是 ReMe 的本地 Web 工作区。你可以在这里浏览和编辑
## 环境要求
-- Node.js 22.13 或更高版本。
- Python 3.11 或更高版本,并已安装 ReMe。
- 正在运行的 ReMe HTTP 服务。Agent 对话还需要可用的 Agent 和模型配置。
+- 只有从源码开发或构建 Studio 时才需要 Node.js 22.13 或更高版本。
ReMe 的安装和后端配置请参阅[仓库中文 README](../README_ZH.md)。