analysis_claude_code/docs/ja/s07-task-system.md
2026-02-24 01:44:44 +08:00

176 lines
6.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# s07: Tasks
> タスクを依存グラフ付き JSON として永続化し、コンテキスト圧縮後も状態を保持し、複数エージェントで共有できるようにする。
## 問題
インメモリ状態s03 の TodoManager などは、s06 の圧縮後に失われやすい。古いターンが要約化されると、Todo 状態は会話の外に残らない。
s06 -> s07 の本質は次の切替:
1. メモリ上 Todo は会話依存で失われやすい。
2. ディスク上 Task は永続で復元しやすい。
さらに可視性の問題がある。インメモリ構造はプロセスローカルであり、チームメイト間の共有が不安定になる。
## Task vs Todo: 使い分け
s07 以降は Task がデフォルト。Todo は短い直線的チェックリスト用に残る。
## クイック判定マトリクス
| 状況 | 優先 | 理由 |
|---|---|---|
| 短時間・単一セッション・直線的チェック | Todo | 儀式が最小で記録が速い |
| セッション跨ぎ・依存関係・複数担当 | Task | 永続性、依存表現、協調可視性が必要 |
| 迷う場合 | Task | 後で簡略化する方が、途中移行より低コスト |
## 解決策
```
.tasks/
task_1.json {"id":1, "status":"completed", ...}
task_2.json {"id":2, "blockedBy":[1], "status":"pending"}
task_3.json {"id":3, "blockedBy":[2], "status":"pending"}
Dependency resolution:
+----------+ +----------+ +----------+
| task 1 | --> | task 2 | --> | task 3 |
| complete | | blocked | | blocked |
+----------+ +----------+ +----------+
| ^
+--- completing task 1 removes it from
task 2's blockedBy list
```
## 仕組み
1. TaskManager はタスクごとに1 JSON ファイルで CRUD を提供する。
```python
class TaskManager:
def create(self, subject: str, description: str = "") -> str:
task = {
"id": self._next_id,
"subject": subject,
"description": description,
"status": "pending",
"blockedBy": [],
"blocks": [],
"owner": "",
}
self._save(task)
self._next_id += 1
return json.dumps(task, indent=2)
```
2. タスク完了時、他タスクの依存を解除する。
```python
def _clear_dependency(self, completed_id: int):
for f in self.dir.glob("task_*.json"):
task = json.loads(f.read_text())
if completed_id in task.get("blockedBy", []):
task["blockedBy"].remove(completed_id)
self._save(task)
```
3. `update` が状態遷移と依存配線を担う。
```python
def update(self, task_id, status=None,
add_blocked_by=None, add_blocks=None):
task = self._load(task_id)
if status:
task["status"] = status
if status == "completed":
self._clear_dependency(task_id)
if add_blocks:
task["blocks"] = list(set(task["blocks"] + add_blocks))
for blocked_id in add_blocks:
blocked = self._load(blocked_id)
if task_id not in blocked["blockedBy"]:
blocked["blockedBy"].append(task_id)
self._save(blocked)
self._save(task)
```
4. タスクツール群をディスパッチへ追加する。
```python
TOOL_HANDLERS = {
# ...base tools...
"task_create": lambda **kw: TASKS.create(kw["subject"]),
"task_update": lambda **kw: TASKS.update(kw["task_id"],
kw.get("status")),
"task_list": lambda **kw: TASKS.list_all(),
"task_get": lambda **kw: TASKS.get(kw["task_id"]),
}
```
## 主要コード
依存グラフ付き TaskManager`agents/s07_task_system.py` 46-123行:
```python
class TaskManager:
def __init__(self, tasks_dir: Path):
self.dir = tasks_dir
self.dir.mkdir(exist_ok=True)
self._next_id = self._max_id() + 1
def _load(self, task_id: int) -> dict:
path = self.dir / f"task_{task_id}.json"
return json.loads(path.read_text())
def _save(self, task: dict):
path = self.dir / f"task_{task['id']}.json"
path.write_text(json.dumps(task, indent=2))
def create(self, subject, description=""):
task = {"id": self._next_id, "subject": subject,
"status": "pending", "blockedBy": [],
"blocks": [], "owner": ""}
self._save(task)
self._next_id += 1
return json.dumps(task, indent=2)
def _clear_dependency(self, completed_id):
for f in self.dir.glob("task_*.json"):
task = json.loads(f.read_text())
if completed_id in task.get("blockedBy", []):
task["blockedBy"].remove(completed_id)
self._save(task)
```
## s06 からの変更
| 項目 | Before (s06) | After (s07) |
|---|---|---|
| Tools | 5 | 8 (`task_create/update/list/get`) |
| 状態保存 | メモリのみ | `.tasks/` の JSON |
| 依存関係 | なし | `blockedBy + blocks` グラフ |
| 永続性 | compact で消失 | compact 後も維持 |
## 設計原理
ファイルベース状態は compaction や再起動に強い。依存グラフにより、会話詳細を忘れても実行順序を保てる。これにより、会話中心の状態を作業中心の永続状態へ移せる。
ただし耐久性には運用前提がある。書き込みのたびに task JSON を再読込し、`status/blockedBy` が期待通りか確認してから原子的に保存しないと、並行更新で状態を上書きしやすい。
コース設計上、s07 以降で Task を主線に置くのは、長時間・協調開発の実態に近いから。
## 試してみる
```sh
cd learn-claude-code
python agents/s07_task_system.py
```
例:
1. `Create 3 tasks: "Setup project", "Write code", "Write tests". Make them depend on each other in order.`
2. `List all tasks and show the dependency graph`
3. `Complete task 1 and then list tasks to see task 2 unblocked`
4. `Create a task board for refactoring: parse -> transform -> emit -> test`