--- title: 'Workspace初期化をinitコマンドに切り出しserveの副作用をなくす' state: 'closed' created_at: '2026-07-02T07:02:02Z' updated_at: '2026-07-02T11:59:35Z' assignee: null queued_by: 'yoi ticket' queued_at: '2026-07-02T09:03:56Z' --- ## 背景 現状の Workspace Backend は `yoi-workspace-server serve` 起動時に workspace root を決め、その中で次の初期化を暗黙に実行している。 - `WorkspaceIdentity::load_or_init(workspace_root)` - `.yoi/workspace.toml` が無ければ作る。 - `WorkspaceBackendConfigFile::ensure_local_config_for_workspace(workspace_root)` - `.yoi/workspace-backend.local.toml` が無ければ `resources/workspace-backend.default.toml` からコピーする。 1Workspace=1Backend の現状では、Backend の実行 directory / `--workspace` が workspace root になっている。この前提自体はよいが、`serve` が初期化副作用を持つと、間違った cwd で起動しただけで `.yoi/workspace.toml` や local config が作られる。 Workspace の一回だけ実行されるべき初期化は、明示的な `init` コマンドへ切り出し、`serve` は既に初期化済みの workspace を起動するだけにする。 ## 目的 - Workspace 初期化を明示コマンドに切り出す。 - `serve` 起動時に workspace identity / local config を作らない。 - `serve` は未初期化 workspace に対して typed diagnostic で失敗する。 - 1Workspace=1Backend の前提を保ち、workspace root は Backend 起動対象として明示する。 - 初期化で作る record / local config と、serve/runtime が生成する data を分ける。 - 現状の local filesystem 保存を採用しつつ、Workspace / Project record の将来的な provider 可換性を妨げない。 ## コマンド設計 ### Product CLI `yoi` 側に workspace init と config subcommand を追加する。 ```text yoi workspace init [--workspace ] yoi workspace config default yoi workspace config diff [--workspace ] yoi workspace serve [OPTIONS] ``` `yoi workspace init` は `yoi-workspace-server init` を起動する thin wrapper にする。`yoi` binary は workspace-server crate を直接 link しない現在の境界を保つ。 ### workspace-server CLI `yoi-workspace-server` 側にも init command を追加する。 ```text yoi-workspace-server init [--workspace ] yoi-workspace-server config default yoi-workspace-server config diff [--workspace ] yoi-workspace-server serve [OPTIONS] ``` `--workspace` は既存 `serve` と同様に、未指定なら current directory を workspace root とする。workspace root は canonicalize する。 ## 初期化で作るもの `init` は次を作る。 ```text .yoi/workspace.toml .yoi/workspace-backend.local.toml ``` ### `.yoi/workspace.toml` - Workspace identity record。 - `workspace_id`, `created_at`, `display_name` を持つ。 - 既存ファイルがある場合は parse/validate し、上書きしない。 - 作成は `create_new` semantics を維持し、race 時は既存 record を読み直す。 ### `.yoi/workspace-backend.local.toml` - `resources/workspace-backend.default.toml` からコピーする workspace-local config。 - 既存ファイルがある場合は上書きしない。 - packaged default の最新版は `yoi workspace config default` で参照し、local との差分は `yoi workspace config diff` で確認する。 ## 初期化で作らないもの `init` は Backend / Runtime data を作らない。 - control-plane SQLite DB - embedded Runtime fs-store - logs / pid files - Worker / transcript / ConfigBundle data - Ticket / Objective body これらは config ではなく data / project record / runtime state なので、必要になった時点で各 subsystem が作る。 ## Workspace storage / 正本境界 現状の Workspace 初期化は local filesystem marker を作る実装でよい。ただし、その filesystem layout を Workspace の public API contract として固定しない。 ### 現状の local filesystem record `init` が作る `.yoi/workspace.toml` は local workspace identity marker として扱う。 - 1Workspace=1Backend の現状では、Backend の実行 directory / `--workspace` が workspace root。 - `.yoi/workspace.toml` はその directory を Yoi workspace として識別する local record。 - `workspace_id` は Backend data root の key として使ってよい。 - `.yoi/workspace.toml` の raw path を Browser-facing API / Runtime create API / Worker conversation context の正本識別子として出さない。 ### Backend / Runtime data Backend DB と embedded Runtime fs-store は generated local data であり、Workspace / Project record の正本ではない。 - control-plane SQLite DB は Backend projection / control-plane data。 - embedded Runtime fs-store は Runtime snapshot / Worker snapshot / transcript / ConfigBundle store。 - これらの data path は config で override できても、data 本体は config や workspace identity ではない。 - Browser-facing API に data root、DB path、Runtime store path、raw execution handle を出さない。 ### Project record provider 可換性 Ticket / Objective などの project record は、現状では `.yoi/tickets` / `.yoi/objectives` などの local filesystem backend を正本として扱ってよい。ただし、将来的に provider を差し替えられるよう、init / serve は以下を守る。 - `init` は Ticket / Objective body や provider-specific project record layout を生成しない。 - Backend DB を Ticket / Objective の正本として昇格しない。 - Runtime / Worker identity に `.yoi/tickets/...` などの filesystem path を持たせない。 - Browser-facing API は typed backend / record id 経由で扱い、filesystem path を正本識別子として公開しない。 - 将来 `ProjectRecordBackend` / `TicketBackend` / `ObjectiveBackend` 相当の provider を差し替える余地を残す。 この Ticket の成果物は local filesystem init を整えることだが、正本可換性のために上位 API へ local path を漏らさないことも受け入れ条件に含める。 ## `serve` の挙動変更 `serve` は初期化済み workspace だけを起動する。 変更後: 1. workspace root を決める。 2. `.yoi/workspace.toml` を load する。 3. `.yoi/workspace-backend.local.toml` は作らない。 4. `.yoi/workspace-backend.local.toml` があれば読む。無ければ defaults。 5. resolved `ServerConfig` で Backend を起動する。 `.yoi/workspace.toml` が無い場合は失敗する。 Diagnostic 例: ```text workspace is not initialized at ; run `yoi workspace init --workspace ` first ``` `serve` は `.yoi/workspace-backend.local.toml` が無いだけでは失敗しない方針とする。config file が欠けている場合は code fallback を使う。ただし `init` は通常 `.local` config を作るため、欠落は診断対象にしてよい。 ## 内部 API 整理 Workspace 初期化は reusable な内部関数へ切り出す。 候補: ```rust WorkspaceInitialization::ensure(workspace_root) -> WorkspaceInitializationReport WorkspaceInitialization::load_required(workspace_root) -> WorkspaceIdentity ``` または既存型に近くするなら: ```rust WorkspaceIdentity::init_if_missing(...) WorkspaceIdentity::load_required(...) WorkspaceBackendConfigFile::ensure_local_config_for_workspace(...) ``` 重要なのは、`serve` が `load_or_init` を呼ばないこと。 ## 既存 CLI flag との関係 この Ticket は Workspace Backend config schema の方針を維持し、新規 Backend 設定項目を CLI flag として増やさない。 - `init` に必要なのは `--workspace` だけ。 - `config diff` に必要なのも `--workspace` だけ。 - `serve` の既存 legacy dev flags をこの Ticket で全面削除するかは別判断にする。 - ただし `serve` の初期化副作用は必ずなくす。 ## 実装要件 - `yoi workspace init [--workspace ]` を追加する。 - `yoi workspace config default` / `yoi workspace config diff [--workspace ]` を追加する。 - `yoi-workspace-server config default` / `yoi-workspace-server config diff [--workspace ]` を追加する。 - `yoi-workspace-server init [--workspace ]` を追加する。 - workspace-server 側の help に init を追加する。 - `WorkspaceIdentity` に load-only path を追加する。 - 既存 `load_or_init` は init command 内部用に残してよいが、serve からは呼ばない。 - `serve` から `WorkspaceIdentity::load_or_init(...)` を外す。 - `serve` から `WorkspaceBackendConfigFile::ensure_local_config_for_workspace(...)` を外す。 - 未初期化 workspace の `serve` は typed diagnostic で失敗する。 - `init` は existing workspace identity / local config を上書きしない。 - `init` は data root / DB / embedded Runtime store を作らない。 - `init` は Ticket / Objective など provider-specific project record layout を作らない。 - `serve` / Browser-facing API / Runtime create path に workspace-local filesystem path を正本識別子として漏らさない。 ## 受け入れ条件 - `yoi workspace init [--workspace ]` が使える。 - `yoi workspace config default` が packaged template を表示する。 - `yoi workspace config diff [--workspace ]` が `.local` config と packaged template を比較する。 - `yoi-workspace-server init [--workspace ]` が使える。 - `init` が `.yoi/workspace.toml` と `.yoi/workspace-backend.local.toml` を作る。 - `init` が既存 `.yoi/workspace.toml` / `.yoi/workspace-backend.local.toml` を上書きしない。 - `init` が DB、embedded Runtime fs-store、logs を作らない. - `init` が Ticket / Objective body や provider-specific project record layout を作らない。 - `serve` が `.yoi/workspace.toml` を新規作成しない。 - `serve` が `.yoi/workspace-backend.local.toml` を新規作成しない。 - 未初期化 workspace で `serve` すると、`workspace init` を促す diagnostic で失敗する。 - 初期化済み workspace では `.local` config が存在し、欠けた key は code fallback で解決される。 - Browser-facing API / Runtime create path / Worker conversation context に `.yoi/workspace.toml`、`.yoi/tickets/...`、data root、DB path、Runtime store path が正本識別子として漏れない。 - Project record provider 可換性を妨げないことが code/docs/tests 上で明確になっている。 - Help text が `workspace init`、`workspace config`、`workspace serve` の責務差を説明している。 - Focused tests が init 作成、init idempotency、serve 未初期化拒否、serve 初期化済み起動、config default/diff、data 非作成を確認する。 - `cargo test -p yoi-workspace-server` が通る。 - `cargo test -p yoi` が通る、または CLI parser tests が通る。 - `cargo check -p yoi` が通る。 - `git diff --check` が通る。 - `nix build .#yoi --no-link` が通る。 ## 対象外 - Backend config schema の追加変更。ただし packaged template の参照・diff CLI はこの Ticket の correction として扱う。 - frontend Vite config の管理。 - remote Runtime supervisor。 - secret store 実装。 - existing legacy `serve` flags の全面削除。 - Ticket / Objective init の統合。