···456456# Base directory for local state (memory/skills/heartbeat).
457457file_state_dir: "~/.morph"
458458# Prompt profile context injection.
459459-# Global temporary file cache directory used for inbound/outbound file handling (e.g. Telegram).
459459+# Global temporary file cache directory used for inbound/outbound file handling (e.g. Telegram/Slack tools).
460460file_cache_dir: "~/.cache/morph"
461461file_cache:
462462 # Note: cleanup runs on startup (best-effort).
+49
docs/feat/feat_20260301_slack.md
···143143- [x] PR-3: Mainline 2 (plan progress rendering)
144144- [x] PR-4: Mainline 3 (Slack prompt block)
145145- [x] PR-5: Mainline 4 (heartbeat integration)
146146+147147+## 5) Thread-Scoped History Plan (New)
148148+149149+### Objective
150150+151151+- [x] When inbound message has `thread_ts`, use thread-scoped history/context for addressing + task execution.
152152+- [x] When inbound message has empty `thread_ts`, keep existing channel-scoped behavior.
153153+- [x] Keep bus `conversation_key` unchanged (`slack:<team_id>:<channel_id>`) in V1.
154154+155155+### Design Constraints
156156+157157+- [ ] Do not change `internal/bus/adapters/slack/*` conversation-key grammar in this PR.
158158+- [ ] Do not change outbound thread delivery priority (`extensions.thread_ts` -> `extensions.reply_to` -> envelope `reply_to`).
159159+- [ ] Keep worker serialization scope channel-level in V1 to minimize behavior risk; change only history scope.
160160+161161+### Implementation Checklist
162162+163163+- [x] Add helper: `buildSlackHistoryScopeKey(teamID, channelID, threadTS string)`.
164164+- [x] Keep `slackJob` minimal: do not add duplicated history-scope state.
165165+- [x] Derive history scope key on demand from `team_id` + `channel_id` + `thread_ts`.
166166+- [x] Replace history map indexing from channel conversation key to `HistoryScopeKey`:
167167+- [x] path: worker pre-run snapshot (`history[...]` read).
168168+- [x] path: worker post-run append (`history[...]` write).
169169+- [x] path: ignored inbound append in talkative mode.
170170+- [x] Replace sticky-skills map indexing to `HistoryScopeKey` so thread and channel contexts do not cross-contaminate.
171171+- [x] Keep `ConversationKey` unchanged for bus/hook/daemon metadata.
172172+- [x] Keep `ReplyToMessageID = ThreadTS` in history items (no schema change).
173173+174174+### Test Checklist
175175+176176+- [x] Unit test for scope-key builder:
177177+- [x] no-thread case -> `slack:<team>:<channel>`
178178+- [x] threaded case -> `slack:<team>:<channel>:thread:<thread_ts>`
179179+- [x] Runtime behavior tests:
180180+- [x] same channel + different `thread_ts` -> isolated history contexts
181181+- [x] same `thread_ts` -> shared thread history
182182+- [x] no `thread_ts` -> unchanged channel history behavior
183183+- [x] Regression tests:
184184+- [x] outbound replies still target correct thread
185185+- [x] `slack.group_trigger_mode=smart` still works in both thread and non-thread messages
186186+187187+### Explicit Non-Goals (V1)
188188+189189+- [ ] Do not change memory subject/session key scope (keep current channel scope).
190190+- [ ] Do not add Slack API thread backfill (`conversations.replies`) in this PR.
191191+192192+### Follow-up (V2 Candidate)
193193+194194+- [ ] Add optional thread backfill on first-seen thread to improve cold-start thread context.
+12-9
docs/slack.md
···159159- Bus ordering/sharding key is `conversation_key = slack:<team_id>:<channel_id>`.
160160 Thread is not part of sharding, so different threads in the same channel share the same serialized worker.
161161162162-### Pending: Thread-Aware Context for `smart` Group Trigger
162162+### Status: Thread-Aware Context for `smart` Group Trigger
163163164164-Current limitation:
164164+Implemented in V1:
165165+166166+- Runtime history scope is now thread-aware:
167167+- when `thread_ts` is present, history context is isolated by thread;
168168+- when `thread_ts` is empty, behavior remains channel-scoped.
169169+- This applies to both addressing classification context and main task execution context.
170170+- Bus `conversation_key` remains `slack:<team_id>:<channel_id>` in V1.
165171166166-- In `slack.group_trigger_mode=smart`, when a user first `@` mentions the bot inside an existing thread, the bot knows the current message is in a thread (`thread_ts` is present), but its LLM history is still channel-scoped rather than thread-scoped.
167167-- As a result, the bot may miss earlier messages from that thread, or mix them with unrelated messages from the same channel.
172172+Remaining limitations:
168173169169-Pending requirement:
174174+- History is thread-scoped only for messages observed after runtime start; there is no first-hit thread backfill from Slack API yet.
175175+- Memory subject/session keys are still channel-scoped in V1.
170176171171-- When the bot is triggered from a Slack thread, it should have a reliable way to perceive thread context before deciding or replying.
172172-- At minimum, this means the runtime should provide thread-scoped context to addressing and main task execution, instead of relying only on channel-scoped rolling history.
173173-- Acceptable implementations may include fetching prior thread replies on demand, maintaining thread-specific short-term history, or both.
174174-- The goal is that when a user says "as discussed above" and then `@` mentions the bot in a thread, the bot can understand what "above" refers to within that thread.
177177+- Implementation checklist is tracked in `docs/feat/feat_20260301_slack.md` ("Thread-Scoped History Plan (New)").
175178176179## 11. Heartbeat Delivery
177180