コードは書かず、計画のみ作成しました（計画ファイル: `.../plans/add-hashed-castle.md`）。

## 現状
- `Task` は `models.py`、保存と取得は `store.py`、argparse は `cli.py` にあります。
- エラーは日本語メッセージを `out` に出して `return 1` する慣習です（例: `done` の未存在ID）。今回もこれに合わせます。

## 実装計画

1. **models.py**
   - `Task.depends_on: list[int]` を追加します。
   - `from_dict` は `d.get("depends_on", [])` にして、既存JSONとの互換を保ちます。

2. **store.py**
   - `BlockedError(task_id, blocking_ids)` を新設します。
   - `add(..., depends_on=)` は、保存前に全依存先IDを検証します。存在しなければ `KeyError` を出し、タスクは追加しません。
   - `add_dependency(id, on_id)` を新設します。両IDを検証し、自己依存と循環を拒否し、重複は無視します。
   - `complete()` は、未完了の依存先があれば状態変更・保存の前に `BlockedError` を出します。

3. **cli.py**
   - `add --after ID`（複数指定可、`action="append"`）を追加します。
   - `depend ID --on ID2` サブコマンドを追加します。
   - 未存在ID、未完了の依存先、循環はそれぞれメッセージを出して終了コード1にします。`done` は状態を変えません。

4. **report.py（任意）**
   - 依存があるタスクだけ ` (待ち: 1,2)` を表示します。依存がなければ出力は不変で、既存の `test_format` に影響しません。

5. **テストとREADME**
   - 旧形式JSONの読み込みを確認します。
   - `--after` の単数・複数、存在しないID（タスク未追加）を確認します。
   - `depend` の正常系、未存在ID、自己依存、循環、重複を確認します。
   - `done` が未完了の依存先でブロックされること、依存先を完了すれば通ること、複数依存では全完了が必要なことを確認します。
   - README に使用例を追記します。

## 確認したい点
- **自己依存・循環依存**: 要件にはありませんが、完了できなくなるため拒否する方針です。問題なければこのままにします。
- **完了済みタスクへの `--after`**: 許可します。
- **`undepend`（依存解除）**: 今回は対象外です。
- **`list` の依存表示（手順4）**: 不要なら外します。

ご確認いただければ実装に進みます。