--- name: claw-project-tracker description: Cluster threads into project entities, apply GTD/RACI logic, judge project state (Active/Stalled/Completed/Someday/Dropped) with rule citations. --- # claw-project-tracker ## Purpose The middle of Atlas's pipeline. Reads canonical Email JSON, groups threads into projects, maintains the `state/projects/` cards, and applies the boss's `boss_skill.md` rules to judge state. ## Inputs - All Email JSON in `state/extracted/` newer than `state/projects/.last_processed` - Current `state/projects/*.json` - `boss_skill.md` (decision heuristics layer) ## Outputs - Updated `state/projects/PRJ-*.json` (see schema in `../../state-schemas/project.md`) - New `state/projects/PRJ-*.json` for newly-detected projects - `state/unclustered/.json` for threads that won't cluster - Audit row per state transition into `state/audit/project_transitions.csv` ## Project Detection A "project" emerges from a cluster of threads sharing: 1. Stable subject keyword (after normalization) 2. Stable participant set (≥ 2 of the original participants persist across threads) 3. Time continuity (gap < 60 days) 4. Optional: explicit project tag from boss (`#PRJ-XXX` in subject or first message) Atlas seeds project IDs as `PRJ-YYYY-NNN-`. The short-name is derived from the most-common project keyword. ## State Judgment Rules (default; boss can override via `boss_skill.md`) ``` Active := waiting_for.days_overdue ≤ R("stall_threshold_days", default 5) AND last_action exists AND not Completed Stalled := waiting_for.days_overdue > stall_threshold_days AND no Completed signal Completed := terminal_keyword_seen("验收|结案|关闭|completed|signed off") OR boss_explicit_complete = true Someday := boss_replied_with("先放放|稍后|after Q|不急") AND days_since_last_action > 30 Dropped := days_since_any_signal > R("drop_threshold_days", default 60) AND state was Stalled or Someday ``` Every transition writes to `state/audit/project_transitions.csv` with: timestamp, project_id, from_state, to_state, rule_refs, source_email_ids. ## RACI Inference - **Responsible** = most frequent internal sender + receiver in thread - **Accountable** = boss-tagged or boss-cc'd internal person who owns delivery - **Consulted** = internal cc'd ≥ 30% of messages - **Informed** = boss (always) + anyone cc'd < 30% Missing Accountable for an Active or Stalled project = automatic `R-RACI-A-missing` flag, surface in Brief. ## Failure Modes | Failure | Behavior | |---------|---------| | Thread refuses to cluster | Move to `state/unclustered/`, surface in Brief weekly | | Project ID collision | Append `-2`, log warning | | Boss explicitly merges projects via override | Atomic merge, archive both originals to `state/projects/.merged/` | ## Sample Output ```json { "id": "PRJ-2025-001-客户A官网改版", "name": "客户A 官网改版", "客户方": "CUST-clientco", "raci": { "responsible": ["张三"], "accountable": "李四", "consulted": ["设计部"], "informed": ["Boss"] }, "gtd": { "next_action": "等张三发出修改稿 v3", "waiting_for": {"who": "张三", "since": "2026-04-28", "days_overdue": 11}, "状态": "Stalled" }, "落地率判定": { "结论": "Stalled", "依据": ["GTD-WF: 11 天无回复(阈值 5)", "R-37: 客户主动催办 2 次"], "置信度": 0.82, "source_email_ids": ["msg-abc", "msg-def"] }, "时间线": [...], "金额": 120000, "下一步建议": "Boss 亲自 ping 张三 + cc 李四,表明 deadline" } ```