---
name: llm-wiki-link
description: Register a project's wiki/ directory into the cross-project aggregate via symlink (whitelist mode). Use when user invokes /llm-wiki-link or asks to add a project to the cross-project wiki aggregate.
---

# llm-wiki-link

`llm-wiki-minimal` で運用している各プロジェクトの `wiki/` を、横断集約点に
symlink で登録するスキル。登録後は `/llm-wiki-cross-recall` で全プロジェクト横断
の ripgrep 検索ができるようになる。

## 設計方針

- **集約点**: `~/.claude/llm-wiki-cross/wiki/<project>/` （symlink）
- **ホワイトリスト**: `~/.claude/llm-wiki-cross/whitelist.txt` （改行区切り、`<project-name> <absolute-path-to-wiki>` 形式）
- **機密境界**: `wiki/` 層のみ集約する。`raw/sessions/` は明示除外（生セッションを横断検索に流さない）
- **登録方式**: ホワイトリスト方式（暗黙の自動登録なし、明示的な `/llm-wiki-link <path>` のみ）
- **Audit Trail Tier 1**: 通常登録（衝突なし）は自律実行、symlink 衝突のみユーザー確認
- **recall は read-only 固定**（書き込みは各プロジェクトの `/llm-wiki-promote` の責務）

## 実行フロー（状態遷移）

```mermaid
stateDiagram-v2
  [*] --> 引数取得
  引数取得 --> path検証: project-path
  引数取得 --> abort_usage: 引数なし
  path検証 --> abort_no_dir: 存在しない
  path検証 --> wiki存在チェック
  wiki存在チェック --> abort_no_wiki: wiki/ なし
  wiki存在チェック --> symlink安全性チェック
  symlink安全性チェック --> abort_wiki_is_symlink: wiki/ 自体が symlink
  symlink安全性チェック --> abort_symlink_in_wiki: wiki/ 配下に symlink
  symlink安全性チェック --> name正規化
  name正規化 --> abort_unsafe_name: . / .. / 空
  name正規化 --> 衝突検出
  衝突検出 --> already_linked: 同一 target
  衝突検出 --> abort_conflict: 異なる target
  衝突検出 --> abort_existing_file: 通常ファイル / dir
  衝突検出 --> symlink作成
  symlink作成 --> whitelist追記
  whitelist追記 --> [*]: linked
  abort_usage --> [*]
  abort_no_dir --> [*]
  abort_no_wiki --> [*]
  abort_wiki_is_symlink --> [*]
  abort_symlink_in_wiki --> [*]
  abort_unsafe_name --> [*]
  abort_conflict --> [*]
  abort_existing_file --> [*]
  already_linked --> [*]
```

## 実行手順

### 1. 引数取得

ユーザーから `<project-path>` を受け取る。引数がない場合は使い方を表示して終了：

```
使い方: /llm-wiki-link <project-path>
例:     /llm-wiki-link ~/workspace/my/llm-wiki-minimal
```

### 2. project path 検証

```bash
PROJECT_PATH="$(cd "$1" 2>/dev/null && pwd)"
if [ -z "$PROJECT_PATH" ]; then
  echo "abort: $1 は存在しないディレクトリです"
  exit 1
fi
if [ ! -d "$PROJECT_PATH/wiki" ]; then
  echo "abort: $PROJECT_PATH/wiki が存在しません（llm-wiki-minimal で wiki/ を作ってから再実行してください）"
  exit 1
fi
if [ -L "$PROJECT_PATH/wiki" ]; then
  echo "abort: $PROJECT_PATH/wiki 自体が symlink です（機密境界を保つため登録しません）"
  exit 1
fi
if find "$PROJECT_PATH/wiki" -type l -print -quit 2>/dev/null | grep -q .; then
  echo "abort: $PROJECT_PATH/wiki 配下に symlink が含まれています（機密境界を保つため登録しません）"
  exit 1
fi
```

`wiki/` 自体または配下の symlink を弾くのは、recall 側が `rg --follow` で集約点を辿るため、wiki/ 内に symlink を許すと任意のファイルが横断検索対象になってしまう（設計の「wiki/ のみ集約」が破れる）ことを防ぐため。

### 3. project name 決定

basename を小文字化し、英数字 `.` `_` `-` 以外をハイフンに置換、連続ハイフンを 1 個に縮約、先頭末尾のハイフンを削除：

```bash
PROJECT_NAME="$(basename "$PROJECT_PATH" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9._-]/-/g; s/--*/-/g; s/^-//; s/-$//')"
case "$PROJECT_NAME" in
  ""|"."|"..")
    echo "abort: project name を安全な集約名に変換できません"
    exit 1
    ;;
esac
```

空白だけでなく改行・タブ・制御文字・記号も `-` に置換。`.` `..` への退化も `case` で abort（ディレクトリ参照との混同を防ぐ）。

### 4. 集約ディレクトリ準備

```bash
AGG_DIR="$HOME/.claude/llm-wiki-cross"
mkdir -p "$AGG_DIR/wiki"
touch "$AGG_DIR/whitelist.txt"
```

### 5. 衝突検出

```bash
LINK_PATH="$AGG_DIR/wiki/$PROJECT_NAME"
TARGET="$PROJECT_PATH/wiki"

if [ -L "$LINK_PATH" ]; then
  EXISTING="$(readlink "$LINK_PATH")"
  if [ "$EXISTING" = "$TARGET" ]; then
    echo "already linked: $LINK_PATH -> $TARGET"
    exit 0
  else
    echo "衝突: $LINK_PATH は既に $EXISTING を指しています。"
    echo "既存登録を解除するか、プロジェクトディレクトリ名を変更してから再実行してください。"
    exit 1
  fi
elif [ -e "$LINK_PATH" ]; then
  echo "abort: $LINK_PATH は通常ファイル/ディレクトリです（symlink ではないため上書きしません）"
  exit 1
fi
```

衝突時はユーザー確認を取る（Audit Trail Tier 1 のうち、symlink 衝突のみ承認が必要）。

### 6. symlink + whitelist 追記

```bash
ln -s "$TARGET" "$LINK_PATH"
LINE="$PROJECT_NAME $TARGET"
grep -Fqx "$LINE" "$AGG_DIR/whitelist.txt" 2>/dev/null || printf '%s\n' "$LINE" >> "$AGG_DIR/whitelist.txt"
echo "linked: $PROJECT_NAME -> $TARGET"
```

### 7. 動作確認案内

```
登録完了: $PROJECT_NAME
次のステップ: /llm-wiki-cross-recall <query> で全プロジェクト横断検索できます
```

## ルール

- **`wiki/` 以外を symlink しない**: `raw/` `src/` 等は集約対象外（機密境界）
- **`wiki/` 内に symlink がある場合は登録しない**: recall の `rg --follow` で任意ファイルが集約対象になるのを防ぐ
- **ホワイトリスト明示登録**: 自動スキャン・自動登録は行わない
- **上書き不可**: 既存 symlink の target を勝手に変更しない（force オプションを設けない）
- **引数バリデーション**: project path・wiki/ ディレクトリ存在・symlink 不在・正規化後の名前は必須チェック
- **機密情報スキャンしない**: 登録対象の wiki/ 内容は読み込まず、symlink を張るだけ
