Skip to content
Draft
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
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ jobs:
run: uv sync --only-group dev
- name: Check
run: uv run --no-sync ruff check --output-format=github .
- name: Check docstring coverage
run: uv run --no-sync interrogate src/unilab

ruff-format:
if: github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request'
Expand Down
25 changes: 23 additions & 2 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
with:
# sphinx-multiversion needs full git refs to build every
# whitelisted branch/tag.
fetch-depth: 0

- name: Install uv
uses: astral-sh/setup-uv@v8.0.0
Expand Down Expand Up @@ -105,9 +109,22 @@ jobs:
echo "::warning::UniLab install failed — deploying prose-only docs"
echo "UNILAB_DOCS_SKIP_AUTODOC=1" >> "$GITHUB_ENV"

- name: Build full HTML
- name: Build full HTML (all whitelisted versions)
working-directory: docs/sphinx
# sphinx-multiversion builds one subdirectory per whitelisted ref
# (default: main only; see smv_* in source/conf.py). The prose-only
# fallback still applies — UNILAB_DOCS_SKIP_AUTODOC is honoured by
# conf.py inside each per-version build.
run: uv run --no-sync sphinx-multiversion source build/html

- name: Add root redirect
working-directory: docs/sphinx
# Versioned builds land in build/html/<version>/; send / to main.
run: echo '<meta http-equiv="refresh" content="0; url=main/en/0-index.html">' > build/html/index.html

- name: Remove Sphinx doctree caches
working-directory: docs/sphinx
run: uv run --no-sync sphinx-build -j auto -b html -n source build/html
run: find build/html -type d -name .doctrees -exec rm -rf {} +

- name: Push to UniLab-doc gh-pages
uses: peaceiris/actions-gh-pages@v4
Expand All @@ -118,6 +135,10 @@ jobs:
external_repository: unilabsim/UniLab-doc
publish_branch: gh-pages
publish_dir: docs/sphinx/build/html
# Keep files not touched by this deploy: older version directories
# and the pre-existing root-level pages stay reachable, so old
# external links keep working.
keep_files: true
user_name: "github-actions[bot]"
user_email: "github-actions[bot]@users.noreply.github.com"
commit_message: "docs: deploy from UniLab@${{ github.sha }}"
Expand Down
5 changes: 5 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,11 @@ policy. In brief: define a reviewable outcome, choose the PR base before coding,
link the driving issue, validate the final head, and wait for current-head remote
CI only when the PR base is `main`.

New public interfaces must ship with docstrings; CI enforces the interrogate
floor in `pyproject.toml`. PRs with user-visible changes must add an entry to
the `Unreleased` section of `docs/sphinx/source/changelog.md` as described in
`CONTRIBUTING.md`.

When a change crosses runtime, backend, config, registry, or other public
contracts, link the relevant ADR. Add an ADR only for a new structural decision.
Treat new public contracts, lifecycle/protocol changes, routine CI, support
Expand Down
14 changes: 14 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,20 @@ Use Conventional Commits:
- `test:` test-related change
- `chore:` build or tooling

## Changelog Discipline

Every PR with user-visible changes must add an entry to the `## Unreleased`
section at the top of
[docs/sphinx/source/changelog.md](docs/sphinx/source/changelog.md), grouped
under the bilingual subsections `### Added / 新增`, `### Changed / 变更`, or
`### Fixed / 修复` (create the subsection when it is missing). Entries follow
the released-version style below: English prose first, then the Chinese
translation, with the driving GitHub issue or PR linked (for example
`([#706](https://github.com/Motphys/UniLab/issues/706))`). Purely internal
changes (refactors, test-only, or CI plumbing) may skip the changelog. Release
maintainers rename `## Unreleased` to the version number and PyPI upload date
at release time.

## Pull Request Workflow

1. Choose and record the intended PR base before development.
Expand Down
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ check: format type check-tests
check-tests:
uv run ruff check tests --select F401,F821,F811,F841 --output-format concise

.PHONY: check-docstrings
check-docstrings:
uv run interrogate src/unilab

.PHONY: test
test:
uv run pytest -m "not slow"
Expand Down
3 changes: 2 additions & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# UniLab Documentation

UniLab 的全部文档源码统一在 [`docs/sphinx/`](sphinx/) 下,通过 Sphinx 构建,部署到
<https://unilabsim.github.io/UniLab-doc/>。
<https://unilabsim.github.io/UniLab-doc/>。站点按版本子路径发布(当前仅 `main/`,
如 `/UniLab-doc/main/en/0-index.html`),根路径自动重定向到 `main/`。

发布入口:

Expand Down
3 changes: 2 additions & 1 deletion docs/sphinx/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ source/
├── _static/
└── _templates/
├── sidebar/
│ └── lang_switcher.html # language dropdown in sidebar
│ ├── lang_switcher.html # language dropdown in sidebar
│ └── versioning.html # version dropdown (rendered only under sphinx-multiversion)
└── autosummary/
```

Expand Down
37 changes: 29 additions & 8 deletions docs/sphinx/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@
UniLab 的文档源码全部在这里,**双语平行结构**——`source/en/` 是英文版,`source/zh_CN/`
是中文版,`adr/`、`api_reference/`、`glossary.md`、`changelog.md`、`_static/` 共享。

CI 在 push to `main` 时构建 Sphinx,通过 deploy key 推到独立仓
CI 在 push to `main` 时用 sphinx-multiversion 构建 Sphinx,通过 deploy key 推到独立仓
[`unilabsim/UniLab-doc`](https://github.com/unilabsim/UniLab-doc) 的 `gh-pages` 分支,
由 GitHub Pages 发布到 <https://unilabsim.github.io/UniLab-doc/>。
由 GitHub Pages 发布到 <https://unilabsim.github.io/UniLab-doc/>。站点按版本目录发布
(当前仅 `main/`),根路径重定向到 `main/`。

## 目录结构

Expand Down Expand Up @@ -41,7 +42,8 @@ docs/sphinx/
└── agents/ ← Agent 速查(中文,01-agent-quick-reference.md)
```

URL 模式:`/`(语言 picker)、`/en/...`、`/zh_CN/...`。两种语言路径 1:1 镜像。
URL 模式:`/`(重定向到 `main/en/0-index.html`)、`/main/en/...`、`/main/zh_CN/...`。站点按
版本目录发布(当前仅 `main/`),版本目录内两种语言路径 1:1 镜像。

## 本地构建

Expand Down Expand Up @@ -73,7 +75,8 @@ UNILAB_DOCS_SKIP_AUTODOC=1 uv run --no-project --with-requirements requirements.

CI 工作流在 `.github/workflows/docs.yml`:

- **PR**: prose-only HTML build,跳过 API reference,failed 阻塞 PR
- **PR**: prose-only HTML build(plain `sphinx-build`),跳过 API reference,
failed 阻塞 PR。plain build 下 `versions` 上下文不存在,侧栏版本切换器不渲染
- **push to main**: prose-only build 通过后,`deploy` job 执行完整构建(安装
UniLab + autodoc)并通过 deploy key(`UNILAB_DOC_DEPLOY_KEY` secret)推送到
[`unilabsim/UniLab-doc`](https://github.com/unilabsim/UniLab-doc) 的
Expand All @@ -82,6 +85,19 @@ CI 工作流在 `.github/workflows/docs.yml`:
- **手动**: `workflow_dispatch` 在 `main` 上触发时走同一套构建 + 部署;
在其他分支触发时只做 prose-only build

deploy job 用 `sphinx-multiversion source build/html` 构建,按版本目录发布:
每个白名单 ref 构建到 `build/html/<version>/`(当前白名单只有 `main`,见
`source/conf.py` 的 `smv_*` 配置),随后在 `build/html/index.html` 写入根
redirect(`meta refresh` → `main/en/0-index.html`),再清理各版本目录下的
`.doctrees` 缓存后发布。发布步骤带 `keep_files: true`,旧版本目录和存量根目录
页面不会被覆盖删除,旧外链保持可用。

多版本放行方式:默认 `smv_branch_whitelist = ^(main)$`、`smv_tag_whitelist = ^$`
(不匹配任何 tag)。未来发版时通过环境变量放行,例如在部署环境设置
`SMV_TAG_WHITELIST='^v[1-9]\d*\.\d+\.\d+$'`(分支侧对应
`SMV_BRANCH_WHITELIST`)。注意 `html_baseurl` 当前固定带 `main/` 后缀,启用多版本
前需将其按版本动态化(见 `conf.py` 注释)。

PR 与 push 的检查性构建明确设置 `UNILAB_DOCS_SKIP_AUTODOC=1`,不安装 UniLab
运行时依赖,也不跑 linkcheck。下面的本地发布流程保留为 CI 部署不可用时的
fallback。
Expand All @@ -97,14 +113,18 @@ fallback。
### 本地发布到 UniLab-doc

完整 API 文档在本地构建完成后,把 `docs/sphinx/build/html/` 的内容同步到
`unilabsim/UniLab-doc` 的 `gh-pages` 分支根目录:
`unilabsim/UniLab-doc` 的 `gh-pages` 分支根目录。构建方式与 CI 一致,用
sphinx-multiversion(需要本地有对应 git ref;`main` 分支存在即可,shallow clone
也能构建),构建后补写根 redirect 并清理 `.doctrees`:

```bash
# 在 UniLab 仓库根目录
uv sync
uv pip install -r docs/sphinx/requirements.txt
cd docs/sphinx
uv run --no-sync sphinx-build -j auto -b html -n source build/html
uv run --no-sync sphinx-multiversion source build/html
echo '<meta http-equiv="refresh" content="0; url=main/en/0-index.html">' > build/html/index.html
find build/html -type d -name .doctrees -exec rm -rf {} +
cd ../..
```

Expand All @@ -121,10 +141,11 @@ git -C ../UniLab-doc checkout gh-pages
git -C ../UniLab-doc pull --ff-only
```

同步构建产物并推送:
同步构建产物并推送。**不要加 `--delete`**:CI 发布用 `keep_files: true` 保留旧版本
目录和存量根目录页面,本地手动发布也要保留它们:

```bash
rsync -a --delete --exclude .git docs/sphinx/build/html/ ../UniLab-doc/
rsync -a --exclude .git docs/sphinx/build/html/ ../UniLab-doc/
touch ../UniLab-doc/.nojekyll

SOURCE_SHA=$(git rev-parse --short HEAD)
Expand Down
2 changes: 2 additions & 0 deletions docs/sphinx/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ sphinxcontrib-mermaid>=0.9
sphinx-togglebutton>=0.3
linkify-it-py>=2.0
sphinx-sitemap>=2.6
sphinx-multiversion>=0.2
beautifulsoup4>=4.12
29 changes: 29 additions & 0 deletions docs/sphinx/source/_static/css/custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,35 @@ kbd {
border-color: var(--color-brand-primary);
}

/* ---------- Sidebar version switcher (sphinx-multiversion) ---------- */
.sidebar-version-switcher {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.4rem 0.8rem;
margin: 0 0 0.2rem 0;
}
.sidebar-version-label {
color: var(--color-foreground-secondary);
font-size: 0.85rem;
font-weight: 600;
}
.sidebar-version-select {
flex: 1;
min-width: 0;
padding: 0.35rem 0.6rem;
font-size: 0.85rem;
border: 1px solid var(--color-foreground-border);
border-radius: 6px;
background: var(--color-background-secondary);
color: var(--color-foreground-primary);
cursor: pointer;
appearance: auto;
}
.sidebar-version-select:hover {
border-color: var(--color-brand-primary);
}

/* Hide old body-injected language switcher */
.language-switcher { display: none !important; }
.landing-language-picker { display: none !important; }
17 changes: 17 additions & 0 deletions docs/sphinx/source/_templates/sidebar/versioning.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{# Furo sidebar component: version switcher (sphinx-multiversion).
Renders only under `sphinx-multiversion` builds, which inject `versions`
and `current_version` into the HTML context; plain `sphinx-build` runs
leave `versions` undefined and the guard hides the switcher. #}
{% if versions %}
<div class="sidebar-version-switcher">
<label class="sidebar-version-label" for="version-select">Version</label>
<select id="version-select" class="sidebar-version-select" onchange="location = this.value;">
{%- for item in versions.branches %}
<option value="{{ item.url }}" {% if item == current_version %}selected{% endif %}>{{ item.name }}</option>
{%- endfor %}
{%- for item in versions.tags|reverse %}
<option value="{{ item.url }}" {% if item == current_version %}selected{% endif %}>{{ item.name }}</option>
{%- endfor %}
</select>
</div>
{% endif %}
61 changes: 61 additions & 0 deletions docs/sphinx/source/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,67 @@ UniLab 遵循[语义化版本](https://semver.org/)。本共享页面以中英
PyPI 版本变更与未发布变更;发布日期采用 PyPI 上传日期。完整提交历史请参阅
[UniLab 仓库](https://github.com/unilabsim/UniLab)。

## Unreleased

### Added / 新增

- The documentation site is now versioned with sphinx-multiversion: the `main`
track is published with a version switcher in the navigation bar
([#2584](https://github.com/Motphys/UniLab/pull/2584),
[#706](https://github.com/Motphys/UniLab/issues/706)).
文档站现通过 sphinx-multiversion 版本化:发布 `main` 轨道,并在导航栏提供
版本切换器([#2584](https://github.com/Motphys/UniLab/pull/2584),
[#706](https://github.com/Motphys/UniLab/issues/706))。
- New manager terms reference pages tabulate the built-in reward, observation,
and termination terms
([#2584](https://github.com/Motphys/UniLab/pull/2584),
[#706](https://github.com/Motphys/UniLab/issues/706)).
新增 manager terms 参考页,以表格列出内置 reward、observation 与
termination 项([#2584](https://github.com/Motphys/UniLab/pull/2584),
[#706](https://github.com/Motphys/UniLab/issues/706))。
- New domain randomization (DR) field configuration reference page documents
the supported reset randomization fields
([#2584](https://github.com/Motphys/UniLab/pull/2584),
[#706](https://github.com/Motphys/UniLab/issues/706)).
新增域随机化(DR)字段配置参考页,记录支持的 reset 随机化字段
([#2584](https://github.com/Motphys/UniLab/pull/2584),
[#706](https://github.com/Motphys/UniLab/issues/706))。
- The four algorithm pages (PPO, APPO, SAC, FlashSAC) each gained a
configuration reference section
([#2584](https://github.com/Motphys/UniLab/pull/2584),
[#706](https://github.com/Motphys/UniLab/issues/706)).
四个算法页(PPO、APPO、SAC、FlashSAC)各新增配置参考小节
([#2584](https://github.com/Motphys/UniLab/pull/2584),
[#706](https://github.com/Motphys/UniLab/issues/706))。
- New walkthroughs cover onboarding a new robot and writing a custom reward
term ([#2584](https://github.com/Motphys/UniLab/pull/2584),
[#706](https://github.com/Motphys/UniLab/issues/706)).
新增"接入新机器人"与"自定义 reward"两篇 walkthrough
([#2584](https://github.com/Motphys/UniLab/pull/2584),
[#706](https://github.com/Motphys/UniLab/issues/706))。
- New training diagnostics page
([#2584](https://github.com/Motphys/UniLab/pull/2584),
[#706](https://github.com/Motphys/UniLab/issues/706)).
新增训练诊断页([#2584](https://github.com/Motphys/UniLab/pull/2584),
[#706](https://github.com/Motphys/UniLab/issues/706))。

### Changed / 变更

- High-traffic public interfaces — the Manager protocols in
`unilab.managers.types`, `TorchEnv`, the reset-state transaction, the MDP
observation/action/curriculum/ray terms, and the PPO/APPO/SAC/FlashSAC
config dataclasses — now carry docstrings, and CI enforces an interrogate
docstring-coverage floor (`fail-under = 40` in `pyproject.toml`)
([#2584](https://github.com/Motphys/UniLab/pull/2584),
[#706](https://github.com/Motphys/UniLab/issues/706)).
高频公开接口——`unilab.managers.types` 中的 Manager protocol、
`TorchEnv`、reset-state transaction、MDP
observation/action/curriculum/ray 项,以及 PPO/APPO/SAC/FlashSAC 配置
dataclass——现已补齐 docstring;CI 通过 interrogate 强制执行 docstring
覆盖率门槛(`pyproject.toml` 中 `fail-under = 40`)
([#2584](https://github.com/Motphys/UniLab/pull/2584),
[#706](https://github.com/Motphys/UniLab/issues/706))。

## 1.5.8 (2026-11-05)

### Changed / 变更
Expand Down
20 changes: 19 additions & 1 deletion docs/sphinx/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
"sphinxcontrib.video",
"sphinxcontrib.mermaid",
"sphinx_sitemap",
"sphinx_multiversion",
]
# Only enable autodoc / autosummary when UniLab is importable. Otherwise
# autosummary's recursive import probe blows up the whole build.
Expand Down Expand Up @@ -174,6 +175,18 @@
".rst": "restructuredtext",
}
templates_path = ["_templates"]

# ---------------------------------------------------------------------------
# sphinx-multiversion — build one output subdirectory per whitelisted ref.
# Defaults build only `main` and match no tags; historical releases are out
# of scope for now. When releases are cut, allow them via the environment,
# e.g. SMV_TAG_WHITELIST='^v[1-9]\d*\.\d+\.\d+$'.
# Plain `sphinx-build` ignores these settings.
# ---------------------------------------------------------------------------
smv_remote_whitelist = r"^.*$"
smv_branch_whitelist = os.getenv("SMV_BRANCH_WHITELIST", r"^(main)$")
smv_tag_whitelist = os.getenv("SMV_TAG_WHITELIST", r"^$")

exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
# When autodoc is disabled, skip the entire API reference tree — its pages
# only contain autosummary directives that would otherwise fail.
Expand All @@ -193,13 +206,18 @@
html_css_files = ["css/custom.css"]
html_favicon = None # add _static/favicon.ico when ready
# html_logo = "_static/images/logo.png"
html_baseurl = "https://unilabsim.github.io/UniLab-doc/"
# The site is published one subdirectory per version by sphinx-multiversion
# (currently only `main`), so canonical URLs live under /UniLab-doc/main/.
# If more versions are ever enabled, this must become version-aware (e.g.
# derived from the smv env vars) so each version's sitemap is correct.
html_baseurl = "https://unilabsim.github.io/UniLab-doc/main/"
sitemap_url_scheme = "{link}"

html_sidebars = {
"**": [
"sidebar/brand.html",
"sidebar/lang_switcher.html",
"sidebar/versioning.html",
"sidebar/search.html",
"sidebar/scroll-start.html",
"sidebar/navigation.html",
Expand Down
Loading