monorepo-setup-worktrees

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Monorepo Worktree System

单体仓库(Monorepo)工作区系统

Scope-based worktree isolation for parallel development streams. Each worktree gets isolated Docker services, databases, and domains.
基于作用域的工作区隔离,支持并行开发流。每个工作区都拥有独立的Docker服务、数据库和域名。

Scopes

作用域(Scopes)

ScopeServicesContainersCreate time
elements
Elements runner + dev-projects only2~28s
web
Elements + telecine core (web, hasura, valkey, maintenance)8~1:30
render
Elements + telecine core + render pipeline (workers, scheduler)~22~2:30
Upgrade path:
elements
web
render
. Downgrade not supported.
作用域服务内容容器数量创建时间
elements
仅包含Elements运行器和dev-projects2~28秒
web
Elements + Telecine核心服务(web、hasura、valkey、维护服务)8~1分30秒
render
Elements + Telecine核心服务 + 渲染流水线(工作节点、调度器)~22~2分30秒
升级路径:
elements
web
render
。不支持降级操作。

Worktree Management

工作区管理

All worktree operations use the unified CLI:
scripts/worktree <command>
.
bash
worktree create <branch> [scope]       # Create new worktree (default: web)
worktree list                          # List all worktrees
worktree status [branch]               # Health check
worktree pause <branch>                # Stop containers
worktree resume <branch>               # Start containers
worktree remove <branch> [--force]     # Full cleanup
worktree upgrade <branch> <scope>      # Escalate scope (elements→web→render)
worktree merge <branch>                # Merge branch into main (feature → main)
worktree pull                          # Fetch upstream, update local main, sync main → all worktrees
worktree prune [--dry-run]             # Remove worktrees whose branches are fully merged into main
worktree smoke <branch>                # One-shot render verification
worktree logs [branch] [options]       # View logs
worktree doctor [branch] [--skills]    # Diagnose issues
worktree editor-deps [branch]          # Install host-side node_modules for editor tooling
worktree deps [--workspace=...]        # Show dependency graph
所有工作区操作均使用统一CLI:
scripts/worktree <command>
bash
worktree create <branch> [scope]       # 创建新工作区(默认作用域:web)
worktree list                          # 列出所有工作区
worktree status [branch]               # 健康检查
worktree pause <branch>                # 停止容器
worktree resume <branch>               # 启动容器
worktree remove <branch> [--force]     # 完全清理
worktree upgrade <branch> <scope>      # 升级作用域(elements→web→render)
worktree merge <branch>                # 将分支合并到main(特性分支→主分支)
worktree pull                          # 获取上游代码、更新本地main分支、同步main到所有工作区
worktree prune [--dry-run]             # 删除已完全合并到main的工作区分支
worktree smoke <branch>                # 一次性渲染验证
worktree logs [branch] [options]       # 查看日志
worktree doctor [branch] [--skills]    # 诊断问题
worktree editor-deps [branch]          # 为编辑器工具安装主机端node_modules
worktree deps [--workspace=...]        # 显示依赖关系图

Architecture

架构

Repo layout

代码库布局

~/Editframe/
  monorepo -> worktrees/main/monorepo   (symlink for convenience)
  worktrees/
    main/
      .worktree-scope               # scope for main (e.g. "render")
      monorepo/                     # primary monorepo checkout [main]
        telecine -> ../telecine     # symlink
        elements -> ../elements     # symlink
      telecine/                     # primary telecine clone [main]
      elements/                     # primary elements clone [main]
    <branch>/
      .worktree-scope               # scope for this branch
      monorepo/                     # monorepo worktree [branch]
      telecine/                     # telecine git worktree [branch]
      elements/                     # elements git worktree [branch]
The main worktree (
worktrees/main/
) must always be on the
main
branch.
Never run
git checkout
,
git switch
, or any branch-switching command in the main worktree directories. All feature work lives in a dedicated branch worktree created with
worktree create
. An LLM agent is most likely to violate this by running
git checkout <branch>
directly, treating the main worktree like a normal single-checkout repo, or using merge patterns that require a prior checkout.
scripts/worktree.ts
enforces this with two hard guards — do not remove or relax them:
  1. cmdCreate
    asserts the main worktree is on
    main
    before creating any new worktree, and always bases new branches off
    main
    .
  2. cmdMerge
    asserts each repo is already on
    main
    and merges without a checkout — never calls
    git checkout
    in the main worktree.
~/Editframe/monorepo
is a convenience symlink and the entry point for all worktree commands.
~/Editframe/
  monorepo -> worktrees/main/monorepo   (方便使用的符号链接)
  worktrees/
    main/
      .worktree-scope               # main分支的作用域(例如:"render")
      monorepo/                     # 主单体仓库检出目录 [main]
        telecine -> ../telecine     # 符号链接
        elements -> ../elements     # 符号链接
      telecine/                     # Telecine主分支的主克隆目录 [main]
      elements/                     # Elements主分支的主克隆目录 [main]
    <branch>/
      .worktree-scope               # 当前分支的作用域
      monorepo/                     # 单体仓库工作区 [分支]
      telecine/                     # Telecine Git工作区 [分支]
      elements/                     # Elements Git工作区 [分支]
主工作区(
worktrees/main/
)必须始终处于
main
分支
。绝不要在主工作区目录中运行
git checkout
git switch
或任何分支切换命令。所有特性开发工作都应在通过
worktree create
创建的专用分支工作区中进行。LLM Agent很可能会违反此规则,直接运行
git checkout <branch>
,将主工作区当作普通单检出代码库处理,或使用需要提前切换分支的合并模式。
scripts/worktree.ts
通过两个严格的防护措施强制执行此规则——请勿移除或放宽这些限制:
  1. cmdCreate
    在创建任何新工作区之前,会验证主工作区是否处于
    main
    分支,并且始终基于
    main
    分支创建新分支。
  2. cmdMerge
    会验证每个代码库已处于
    main
    分支,并在不切换分支的情况下完成合并——绝不会在主工作区中调用
    git checkout
~/Editframe/monorepo
是一个便利的符号链接,也是所有工作区命令的入口点。

Working in a branch worktree as an agent

Agent在分支工作区中的操作方式

An agent's working directory is fixed at launch — typically
worktrees/main/monorepo
. There is no persistent
cd
.
After creating or identifying a branch worktree, every file edit, git command, and script invocation must use the full absolute path rooted at the branch worktree, not a relative path from the agent's cwd.
Given branch
my-feature
the worktree root is
~/Editframe/worktrees/my-feature/monorepo/
. Concrete rules:
  • File reads/edits: absolute paths under
    ~/Editframe/worktrees/my-feature/monorepo/
  • Git operations:
    git -C ~/Editframe/worktrees/my-feature/monorepo <command>
    or use the
    workdir
    parameter in tool calls
  • Elements scripts:
    ~/Editframe/worktrees/my-feature/elements/scripts/<script>
  • Telecine scripts:
    ~/Editframe/worktrees/my-feature/telecine/scripts/<script>
  • Never use relative paths or paths under
    worktrees/main/
    for branch work
To find the root for an existing branch:
git worktree list | grep my-feature
EDITFRAME_DIR
in scripts is always
$(dirname $(dirname $(dirname $(git rev-parse --show-toplevel))))
— three levels up from the monorepo checkout path.
Agent的工作目录在启动时是固定的——通常为
worktrees/main/monorepo
不存在持久化的
cd
操作
。创建或定位到分支工作区后,所有文件编辑、Git命令和脚本调用都必须使用分支工作区根目录的完整绝对路径,而非相对于Agent当前工作目录的相对路径。
假设分支名为
my-feature
,其工作区根目录为
~/Editframe/worktrees/my-feature/monorepo/
。具体规则如下:
  • 文件读取/编辑:使用
    ~/Editframe/worktrees/my-feature/monorepo/
    下的绝对路径
  • Git操作:使用
    git -C ~/Editframe/worktrees/my-feature/monorepo <command>
    ,或在工具调用中使用
    workdir
    参数
  • Elements脚本
    ~/Editframe/worktrees/my-feature/elements/scripts/<script>
  • Telecine脚本
    ~/Editframe/worktrees/my-feature/telecine/scripts/<script>
  • 绝不要使用相对路径或
    worktrees/main/
    下的路径进行分支工作
查找现有分支的根目录:
git worktree list | grep my-feature
脚本中的
EDITFRAME_DIR
始终为
$(dirname $(dirname $(dirname $(git rev-parse --show-toplevel))))
——即单体仓库检出路径向上三级目录。

Shared infrastructure

共享基础设施

  • editframe-postgres
    — single shared PostgreSQL, each worktree gets its own database (
    telecine-<branch>
    )
  • editframe-traefik
    — shared reverse proxy, routes by
    Host
    header (
    <branch>.localhost
    )
  • telecine-runner
    /
    elements-runner
    — shared Docker images (not rebuilt per worktree)
  • editframe-postgres
    —— 单个共享PostgreSQL实例,每个工作区拥有自己的数据库(
    telecine-<branch>
  • editframe-traefik
    —— 共享反向代理,通过
    Host
    头路由(
    <branch>.localhost
  • telecine-runner
    /
    elements-runner
    —— 共享Docker镜像(不会为每个工作区重新构建)

Database template

数据库模板

telecine-template
is cloned from
telecine-main
(304 migrations + seed data, ~0.6s clone). Template auto-refreshes when
telecine/scripts/start
runs migrations on main.
telecine-template
克隆自
telecine-main
(包含304个迁移文件和种子数据,克隆耗时约0.6秒)。当
telecine/scripts/start
在main分支上运行迁移时,模板会自动刷新。

Port offsets

端口偏移

Worktree services use
cksum
-based port offsets (200 slots, spacing of 100) so host tools like Postico can connect. Main worktree uses standard ports.
工作区服务使用基于
cksum
的端口偏移(200个可用槽位,间隔为100),以便Postico等主机工具可以连接。主工作区使用标准端口。

Config scripts

配置脚本

  • telecine/scripts/worktree-config
    — exports
    WORKTREE_ID
    ,
    WORKTREE_DATABASE
    ,
    WORKTREE_DOMAIN
    ,
    WORKTREE_DOCKER_PROJECT_NAME
    , port variables
  • elements/scripts/worktree-config
    — same pattern for elements
  • .worktree-scope
    file in monorepo worktree root tracks current scope
  • telecine/scripts/worktree-config
    —— 导出
    WORKTREE_ID
    WORKTREE_DATABASE
    WORKTREE_DOMAIN
    WORKTREE_DOCKER_PROJECT_NAME
    及端口变量
  • elements/scripts/worktree-config
    —— Elements采用相同的配置模式
  • 单体仓库工作区根目录下的
    .worktree-scope
    文件跟踪当前作用域

Docker Compose profiles

Docker Compose配置文件

  • No profile = core services (always start): runner, web, valkey, graphql-engine, data-connector-agent, maintenance
  • render
    profile: all worker services, scheduler-go, jit-transcoding
  • dev
    profile: tracing, otel-viewer, mailhog, playwright
  • telecine/scripts/start
    reads
    .worktree-scope
    to set
    COMPOSE_PROFILES
  • 无配置文件 = 核心服务(始终启动):运行器、web、valkey、graphql-engine、data-connector-agent、维护服务
  • render
    配置文件:所有工作节点服务、scheduler-go、即时转码服务
  • dev
    配置文件:链路追踪、otel-viewer、mailhog、playwright
  • telecine/scripts/start
    读取
    .worktree-scope
    来设置
    COMPOSE_PROFILES

Service startup ordering

服务启动顺序

Runner must start and
npm install
must complete before other services that execute application code (web, dev-projects, workers). The create and upgrade scripts handle this:
up -d runner
npm install
up -d
(remaining services).
运行器必须先启动,且
npm install
必须完成后,才能启动其他执行应用代码的服务(web、dev-projects、工作节点)。创建和升级脚本会处理此顺序:
up -d runner
npm install
up -d
(剩余服务)。

Syncing main into worktrees

将main分支同步到工作区

After PRs merge to main (which happens frequently), run
worktree pull
from the main worktree:
bash
worktree pull
This does three things in sequence:
  1. Fetches upstream remotes for monorepo, telecine, and elements
  2. Merges
    origin/main
    into local main for telecine and elements (fast-forward when clean)
  3. Merges local main into every active worktree branch
Conflicts in
package.json
,
package-lock.json
, and
VERSION.ts
are auto-resolved by accepting main's version. All other conflicts are reported and skipped — the affected worktree is left untouched for manual resolution.
To clean up worktrees whose branches have been fully merged into main across all three repos:
bash
worktree prune           # remove all fully-merged worktrees
worktree prune --dry-run # preview what would be removed
prune
checks all three repos before removing anything — a worktree is only pruned when its branch is an ancestor of main in monorepo, telecine, and elements simultaneously.
当PR频繁合并到main分支后,在主工作区中运行
worktree pull
bash
worktree pull
该命令会依次执行以下三个操作:
  1. 获取单体仓库、Telecine和Elements的上游远程代码
  2. origin/main
    合并到Telecine和Elements的本地main分支(无冲突时执行快进合并)
  3. 将本地main分支合并到每个活跃的工作区分支
package.json
package-lock.json
VERSION.ts
中的冲突会自动通过接受main分支的版本来解决。所有其他冲突会被报告并跳过——受影响的工作区会保持原样,等待手动解决。
要清理已在所有三个代码库中完全合并到main分支的工作区:
bash
worktree prune           # 删除所有已完全合并的工作区
worktree prune --dry-run # 预览将要删除的内容
prune
命令会检查所有三个代码库后再执行删除操作——只有当工作区分支在单体仓库、Telecine和Elements中同时是main分支的祖先时,才会被清理。

Worktree lifecycle

工作区生命周期

create (elements, 28s) → upgrade (web, 63s) → upgrade (render)
     ↓                         ↓
  pause/resume             pause/resume
   remove
create(elements,28秒)→ upgrade(web,63秒)→ upgrade(render)
     ↓                         ↓
  pause/resume             pause/resume
   remove

Dev Server URLs

开发服务器URL

The elements dev-projects Vite server uses
root: elements/dev-projects/
. Files are served at the root path — not under
/dev-projects/
.
  • video.html
    http://<branch>.localhost:4321/video.html
  • canvas-demo.html
    http://<branch>.localhost:4321/canvas-demo.html
Never include
dev-projects/
in the URL path.
Elements dev-projects Vite服务器使用
root: elements/dev-projects/
。文件在根路径下提供服务——不要放在
/dev-projects/
路径下。
  • video.html
    http://<branch>.localhost:4321/video.html
  • canvas-demo.html
    http://<branch>.localhost:4321/canvas-demo.html
绝不要在URL路径中包含
dev-projects/

dev-projects in worktrees

工作区中的dev-projects

elements/dev-projects/
is gitignored. Worktrees would only have committed stubs without the full asset/src tree.
worktree create
sets
DEV_PROJECTS_HOST
in the worktree's
elements/.env
to point at main's dev-projects. The
docker-compose.yaml
dev-projects service mounts this path over
/packages/dev-projects
, so the worktree's dev server always has the full file tree from main.
elements/dev-projects/
已被Git忽略。工作区默认只会包含已提交的存根文件,而非完整的资源/源码目录。
worktree create
会在工作区的
elements/.env
中设置
DEV_PROJECTS_HOST
,指向main分支的dev-projects。
docker-compose.yaml
中的dev-projects服务会将该路径挂载到
/packages/dev-projects
,因此工作区的开发服务器始终可以使用main分支中的完整文件目录。

Smoke testing

冒烟测试

worktree smoke <branch>
is a one-shot render verification. It's not a persistent scope; use it as a pre-merge gate for render pipeline changes.
  1. Requires
    web
    or
    render
    scope (errors on
    elements
    )
  2. If scope is
    web
    : temporarily starts render-profile services, registers a cleanup trap to stop them on exit
  3. If scope is
    render
    : runs against already-running services, no lifecycle management
  4. Runs
    telecine/scripts/smoke-test.ts
    inside the runner container with
    EF_HOST=http://web:3000
    and the worktree's
    EF_TOKEN
  5. Prints the dashboard URL (
    http://<branch>.localhost:3000
    ) for visual inspection of render outputs
  6. Prompts to press enter before stopping render services (if they were started)
Render development workflow: stay at
web
scope, run unit tests directly, use
worktree smoke
as the merge gate rather than keeping a full render stack running all day.
scheduler-go
is a pre-built Go image not managed by docker-compose.
worktree smoke
builds it automatically on first run.
scripts/build-runner-images
also builds it.
worktree smoke <branch>
是一次性渲染验证。它不是持久化作用域;可将其作为渲染流水线变更的预合并检查环节。
  1. 需要
    web
    render
    作用域(使用
    elements
    作用域会报错)
  2. 如果是
    web
    作用域:临时启动render配置文件中的服务,并注册清理陷阱以在退出时停止这些服务
  3. 如果是
    render
    作用域:针对已运行的服务执行测试,不进行生命周期管理
  4. 在运行器容器中执行
    telecine/scripts/smoke-test.ts
    ,使用
    EF_HOST=http://web:3000
    和工作区的
    EF_TOKEN
  5. 打印仪表盘URL(
    http://<branch>.localhost:3000
    ),用于可视化检查渲染输出
  6. 在停止渲染服务(如果已启动)前,提示按回车键确认
渲染开发工作流:保持在
web
作用域,直接运行单元测试,使用
worktree smoke
作为合并检查环节,而非全天运行完整的渲染栈。
scheduler-go
是预构建的Go镜像,不由docker-compose管理。
worktree smoke
会在首次运行时自动构建它。
scripts/build-runner-images
也可用于构建该镜像。

Editor tooling

编辑器工具

Docker containers use named volumes for
node_modules
, which are invisible to the host filesystem. The host-side editor (VS Code, Cursor, etc.) needs its own
node_modules
to resolve TypeScript types and JSX intrinsics.
worktree create
installs host-side deps automatically with
npm install --ignore-scripts
. For existing worktrees missing host types, run
worktree editor-deps <branch>
.
worktree doctor
detects and reports missing host-side types.
Docker容器使用命名卷存储
node_modules
,这些卷对主机文件系统不可见。主机端编辑器(VS Code、Cursor等)需要自己的
node_modules
来解析TypeScript类型和JSX内置组件。
worktree create
会自动使用
npm install --ignore-scripts
安装主机端依赖。对于缺少主机端类型的现有工作区,运行
worktree editor-deps <branch>
worktree doctor
会检测并报告缺失的主机端类型。

Troubleshooting

故障排除

  • Port conflict: two branches hashed to same offset. Extremely unlikely with cksum/200 slots but possible. Remove one worktree and recreate.
  • Orphaned containers:
    worktree doctor
    detects orphaned projects (containers with no matching git worktree) and prints the exact
    docker rm -f
    command to clean them up.
  • Partial create failure: if
    worktree create
    fails partway through, the worktree directory exists but is incomplete. Run
    worktree remove --force <branch>
    before retrying.
  • Stale template: run
    scripts/update-template-db
    to refresh from current main DB state.
  • 端口冲突:两个分支哈希到相同的偏移量。虽然使用cksum/200槽位时概率极低,但仍有可能发生。删除其中一个工作区并重新创建。
  • 孤立容器
    worktree doctor
    会检测孤立项目(无匹配Git工作区的容器),并打印用于清理的精确
    docker rm -f
    命令。
  • 创建失败:如果
    worktree create
    中途失败,工作区目录已存在但不完整。重新尝试前运行
    worktree remove --force <branch>
  • 模板过期:运行
    scripts/update-template-db
    从当前main分支数据库状态刷新模板。