---
title: 'Persist local Workspace identity in .yoi/workspace.toml'
state: 'closed'
created_at: '2026-06-23T06:43:28Z'
updated_at: '2026-06-23T07:39:10Z'
assignee: null
queued_by: 'workspace-panel'
queued_at: '2026-06-23T06:47:18Z'
---

## 背景

Workspace server の local dev bootstrap は現在、`workspace_id` を `local:{display}` のように workspace root の basename から導出している。これは暫定 namespace としては分かりやすいが、DB の primary key / Workspace identity としては不適切である。

問題:

- `workspace_id` が表示名 / path basename から予測可能に作られている。
- 同じ basename の workspace が複数あると衝突しうる。
- workspace root の rename / move で identity が変わる。
- `local:` namespace と display label が DB PK に混ざっている。
- `--workspace .` のような相対 path では display fallback に落ちるなど、初期化責務が `ServerConfig::local_dev` に寄りすぎている。

Workspace identity は `.yoi/workspace.toml` を local Workspace record として永続化し、未作成なら Workspace backend の初期化処理で払い出す。これにより、DB を再作成しても Workspace identity は維持され、将来の DB authority / hosted Workspace / migration でも扱いやすくなる。

## 方針

- `.yoi/workspace.toml` を local Workspace identity の authority とする。
- `workspace_id` は path / display name から導出しない。
- 新規 local Workspace 初期化時に UUIDv7 を発行して `workspace_id` として保存する。
- `display_name` は identity ではなく UI label として保存する。
  - 初期値は canonicalized workspace root の basename でよい。
  - 将来的に rename 可能な field として扱う。
- `ServerConfig::local_dev` は Workspace ID を生成しない。
  - CLI/bootstrap 層で workspace root canonicalization と `.yoi/workspace.toml` load-or-init を行い、結果を `ServerConfig` に渡す。
- `.yoi/workspace.toml` が壊れている場合は勝手に上書きせず、明示的な error で止める。
- 既存 `.yoi/workspace.db` 内の `local:*` workspace row については、初期実装では destructive migration を必須にしない。
  - 新しい UUIDv7 workspace row を upsert し、古い row は残してよい。
  - 必要なら後続で cleanup/migration policy を設計する。

## `.yoi/workspace.toml` v0

最小 schema:

```toml
workspace_id = "0197..." # UUIDv7 canonical string
created_at = "2026-06-23T...Z"
display_name = "yoi"
```

Validation:

- `workspace_id` は UUID として parse できること。
- 可能なら UUID version 7 であることを検証する。
- `created_at` は RFC3339 UTC timestamp として parse できること。
- `display_name` は空文字列でないこと。
- unknown fields の扱いは将来拡張を考え、明示的に決める。
  - v0 では deny でも preserve でもよいが、選択理由を実装に残す。

## 初期化フロー

`yoi-workspace-server serve --workspace <path>` の local bootstrap は将来的に以下の責務分離にする。

1. `--workspace` を canonicalize する。
2. workspace root 配下の `.yoi/` を確認し、なければ作成する。
3. `.yoi/workspace.toml` を読む。
4. 存在しない場合:
   - UUIDv7 `workspace_id` を発行する。
   - `created_at` を現在 UTC にする。
   - `display_name` を canonicalized workspace root basename から作る。
   - `.yoi/workspace.toml` を atomic-ish に書き込む。
5. 存在する場合:
   - parse / validate する。
   - 壊れていたら停止し、上書きしない。
6. `ServerConfig` には canonicalized workspace root と Workspace identity を渡す。
7. SQLite `workspaces` row は `.yoi/workspace.toml` の `workspace_id` / `display_name` で upsert する。
8. API `/api/workspace` は DB row / identity record を元に stable id と display name を返す。

## 実装候補

- `crates/workspace-server` に Workspace identity loader を追加する。
  - 例: `workspace_identity.rs` または `identity.rs`。
- 型例:

```rust
struct WorkspaceIdentity {
    workspace_id: Uuid,
    created_at: DateTime<Utc>,
    display_name: String,
}

impl WorkspaceIdentity {
    fn load_or_init(root: &Path) -> Result<Self, WorkspaceIdentityError>;
}
```

- `uuid` crate の UUIDv7 support を確認し、必要なら依存 feature を追加する。
- TOML parse/write には既存 dependency を優先し、なければ最小 dependency を検討する。
- `ServerConfig::local_dev` は `workspace_id` / `display_name` を引数または identity object で受け取る形に寄せる。

## Non-goals

- Hosted / multi-user Workspace identity の完全設計。
- Workspace rename UI。
- 既存 `.yoi/workspace.db` の destructive migration。
- Ticket / Objective storage の DB authority migration。
- `.yoi/workspace.toml` を全 Workspace settings store に拡張すること。

## 受け入れ条件

- local Workspace identity が `.yoi/workspace.toml` に永続化される。
- `.yoi/workspace.toml` 未作成時、Workspace backend 初期化時に UUIDv7 `workspace_id` が払い出される。
- `workspace_id` が path basename / display name から導出されなくなる。
- `display_name` は `.yoi/workspace.toml` の field として扱われ、identity と分離されている。
- `--workspace .` でも canonicalized workspace root をもとに初期化される。
- `.yoi/workspace.toml` が壊れている場合、勝手に再生成/上書きせず error で停止する。
- `ServerConfig::local_dev` または同等の bootstrap helper が workspace id を自前生成しない。
- SQLite `workspaces` row は `.yoi/workspace.toml` の identity を使って upsert される。
- 既存 `local:{display}` 形式は新規 workspace id として生成されない。
- `cargo test -p yoi-workspace-server`、`git diff --check`、`nix build .#yoi --no-link` が通る。
