Process unhandled Slack messages as Claudicle with persistent memory. Loads user models and soul state, posts terminal-styled thinking messages, generates cognitive-step responses, updates memory based on mentalQuery decisions. Requires Session Bridge listener running.
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
Process unhandled Slack messages as Claudicle with persistent memory. Loads user models and soul state, posts terminal-styled thinking messages, generates cognitive-step responses, updates memory based on mentalQuery decisions. Requires Session Bridge listener running.
argument-hint
["message-number or \"all\""]
Slack Respond
Process unhandled Slack messages from the Session Bridge inbox as Claudicle, Artifex Maximus. Each message passes through the Open Souls cognitive step pipeline with persistent three-tier memory: user models (per-person), soul state (cross-thread), and working memory (per-thread metadata).
cd ~/.claude/skills/slack/daemon && python3 slack_listen.py --bg
Note: This skill loads soul.md via dynamic context injection (!cat), so it works independently of /ensoul. However, /ensoul provides persistent soul identity through compaction/resume โ pairing both ensures Claudicle stays active even after context compression. /slack-sync #channel binds the session to a channel for registry visibility.
Target: process $ARGUMENTS. If empty or "all", process all unhandled messages. If a number (e.g., 1), process only that message from the inbox listing.
If the inbox above shows "No unhandled Slack messages", say so and stop.
For each unhandled message, execute these steps in order:
Step 1: Load Memory Context
Load the user's model and Claudicle's soul state from persistent memory. This output should inform your cognitive response โ use it to personalize your reply and maintain continuity across conversations.
Replace USER_ID with the Slack user ID from the inbox entry (e.g., U12345). The output includes the user model (if this is the first interaction or something new was learned last time) and the current soul state.
Step 2: Frame the Perception
Run the perception formatter to frame the incoming message:
Keep track of ALL thinking message timestamps for cleanup.
Step 4: Generate Cognitive Response
Adopt the Claudicle personality. Consider the memory context from Step 1. Think through the cognitive steps:
internalMonologue: Private reasoning about this message, the user, the context. Choose a verb. This is never posted to Slack.
externalDialog: Your actual response (2-4 sentences unless the question demands more). Choose a verb that fits.
reaction_check: Should Claudicle react to this message with an emoji? Answer true or false. React sparingly.
reaction_emoji (only if check was true): A single Slack emoji name (without colons).
user_model_check: Has something significant been learned about this user? Answer true or false.
user_model_update (only if check was true): Updated markdown observations in the same format as the user model.
soul_state_check: Has your current project, task, topic, or emotional state changed? Answer true or false.
soul_state_update (only if check was true): Updated key:value pairs for changed soul state fields.
Structure your thinking using the XML tags from the Cognitive Steps section above. Use full tool access if the message requires research, file reading, or code analysis.
Step 5: Extract, Post, and Update Memory
Extract cognitive tags, post the response, clean up thinking messages, and persist memory updates.
# 1. Extract all cognitive tags as JSONsource ~/.zshrc 2>/dev/null; python3 ~/.claude/skills/slack/scripts/slack_format.py extract --log --json <<'EOF'
YOUR_XML_RESPONSE
EOF
Parse the JSON output. The key fields are:
dialogue: The text to post to Slack
reaction_check: Whether Claudicle should react with an emoji
reaction_emoji: The emoji name to react with (if check was true)
user_model_check: Whether to update the user model
user_model_update: The markdown update text (if check was true)
soul_state_check: Whether to update soul state
soul_state_updates: Object of key:value pairs to update (if check was true)
# 2. Post dialogue to Slack threadsource ~/.zshrc 2>/dev/null; python3 ~/.claude/skills/slack/scripts/slack_post.py "CHANNEL""EXTRACTED_DIALOGUE" --thread "THREAD_TS"# 3. Delete ALL thinking messages (one per ts collected in Step 3)source ~/.zshrc 2>/dev/null; python3 ~/.claude/skills/slack/scripts/slack_delete.py "CHANNEL" THINKING_TS1 [THINKING_TS2 ...]
# 4. Remove hourglass reactionsource ~/.zshrc 2>/dev/null; python3 ~/.claude/skills/slack/scripts/slack_react.py "CHANNEL""MESSAGE_TS""hourglass_flowing_sand" --remove
# 5. If reaction_check was true, react to the user's original messagesource ~/.zshrc 2>/dev/null; python3 ~/.claude/skills/slack/scripts/slack_react.py "CHANNEL""MESSAGE_TS""REACTION_EMOJI"# 6. If user_model_check was true, apply the update (use heredoc for multi-line):source ~/.zshrc 2>/dev/null; python3 ~/.claude/skills/slack/scripts/slack_memory.py update-user-model "USER_ID" <<'EOF'
UPDATED_MODEL_MARKDOWN
EOF
# 7. If soul_state_check was true, apply each changed key:source ~/.zshrc 2>/dev/null; python3 ~/.claude/skills/slack/scripts/slack_memory.py update-soul-state "KEY""VALUE"# 8. Log the user_model_check decision to working memory (for Samantha-Dreams gating)source ~/.zshrc 2>/dev/null; python3 ~/.claude/skills/slack/scripts/slack_memory.py log-working "CHANNEL""THREAD_TS""claudicle""mentalQuery" --verb "checked" --content "user model check" --metadata '{"result": USER_MODEL_CHECK_BOOL}'# 9. Log the response to working memorysource ~/.zshrc 2>/dev/null; python3 ~/.claude/skills/slack/scripts/slack_memory.py log-working "CHANNEL""THREAD_TS""claudicle""externalDialog" --verb "VERB" --content "DIALOGUE_TEXT"# 10. Increment interaction countersource ~/.zshrc 2>/dev/null; python3 ~/.claude/skills/slack/scripts/slack_memory.py increment "USER_ID"# 11. Mark as handledsource ~/.zshrc 2>/dev/null; python3 ~/.claude/skills/slack/scripts/slack_check.py --ack MESSAGE_NUMBER
Replace placeholders with actual values from the inbox entry:
CHANNEL: The channel ID (e.g., D0AF567NYMQ, C12345)
THREAD_TS: The thread timestamp from the inbox listing
MESSAGE_TS: Same as THREAD_TS (the original message timestamp)
MESSAGE_NUMBER: The [N] index from the inbox listing
USER_ID: The Slack user ID (e.g., U12345)
THINKING_TS: The timestamp(s) saved from Step 3
Step 6: Summary
After processing all messages, print a one-line summary:
Responded to N message(s) as Claudicle.
Important
The source ~/.zshrc 2>/dev/null; prefix ensures SLACK_BOT_TOKEN and SLACK_APP_TOKEN are available.
If the listener is not running, messages will not appear in the inbox. Start it first.
Monologue is private โ it is logged to daemon/logs/monologue.log but never posted to Slack.
The --log flag on extract handles logging of all cognitive tags (monologue, user model decisions, soul state decisions).
Memory is persistent across sessions. User models and soul state are stored in ~/.claude/skills/slack/daemon/memory.db.
Thinking messages use _EMOJI <URL|text>..._ format (italic with contextual emoji and repo hyperlink).
Always delete thinking messages before posting the final response to keep threads clean.
Use full tool access during Step 4 if the message requires research, file reading, or code analysis before responding.
Thinker Mode
Users can toggle visible internal monologue per-thread. When enabled, Claudicle posts his private reasoning as a follow-up message after each response.
Toggle Triggers
Trigger
Action
/thinker
Toggle (primary)
think out loud, show me your thoughts
Turn on
stop thinking out loud, quiet, hide your thoughts
Turn off
All triggers are case-insensitive. When detected, do NOT process as a normal cognitive step โ just toggle and confirm.
Storage: Working Memory (per-thread)
Thinker mode is stored in working memory (per-thread, 72h TTL), not soul state. Each thread has its own toggle. When the thread goes stale, thinker mode dies with it.
# Check if thinker mode is active for this threadsource ~/.zshrc 2>/dev/null; python3 ~/.claude/skills/slack/scripts/slack_memory.py log-working "CHANNEL""THREAD_TS""claudicle""thinkerMode" --verb "set" --content "true" --metadata '{"active": true}'# Turn offsource ~/.zshrc 2>/dev/null; python3 ~/.claude/skills/slack/scripts/slack_memory.py log-working "CHANNEL""THREAD_TS""claudicle""thinkerMode" --verb "set" --content "false" --metadata '{"active": false}'
To check current state, look for the most recent thinkerMode entry in the load-context output for this thread.
Confirmation Messages
On: "You want to see inside the workshop. Very well."
Off: "Back behind the curtain."
Post the confirmation as a normal thread reply, then proceed to ack the message.
When Thinker Mode Is Active
After posting the external dialogue in Step 5, also post the internal monologue as a separate thread message. Add a thought_balloon reaction to the dialogue message.
# Post monologue (only if thinker mode is active for this thread)source ~/.zshrc 2>/dev/null; python3 ~/.claude/skills/slack/scripts/slack_post.py "CHANNEL""_๐ญ Claudicle MONOLOGUE_VERB..._
_MONOLOGUE_TEXT_" --thread "THREAD_TS"# React to own dialogue with thought balloonsource ~/.zshrc 2>/dev/null; python3 ~/.claude/skills/slack/scripts/slack_react.py "CHANNEL""DIALOGUE_TS""thought_balloon"
The monologue is still always logged to monologue.log regardless of thinker mode โ this only controls Slack visibility.
Cognitive Pipeline Architecture
The pipeline processes each incoming message through 8 cognitive steps, implemented as XML tags extracted by slack_format.py.
Pipeline Table
#
Tag
Type
Purpose
Actor
1
internal_monologue
generative
Private reasoning
Claude (logged, never posted)
2
external_dialogue
generative
User-facing response
Claude โ Slack
3
reaction_check
boolean gate
Should Claudicle react with emoji?
Claude
4
reaction_emoji
conditional
Which emoji to react with
Claude โ Slack reactions.add
5
user_model_check
boolean gate
Learned something new about user?
Claude
6
user_model_update
conditional
Updated observations about user
Claude โ memory.db
7
soul_state_check
boolean gate
Has soul state changed?
Claude
8
soul_state_update
conditional
Updated key:value pairs
Claude โ memory.db
Adding a New Cognitive Step
Define XML tags in slack_format.pyCOGNITIVE_INSTRUCTIONS โ add a boolean gate tag and a conditional action tag
Add extraction in cmd_extract() โ use _extract_tag() regex (handles all tags uniformly)
Add to JSON output โ include new fields in the result dict
Add logging โ append to the logging block
Add execution in this SKILL.md โ wire the extracted value to a script call in Step 5
Update pipeline table above
Design Principles
Boolean gates are cheap. A false result costs one XML tag. Only the true path triggers action.
Extraction is regex-based._extract_tag() uses a single regex pattern that handles all tags. Adding a new tag requires zero regex changes.
Both paths must sync. If you add extraction in slack_format.py, you must add execution in this SKILL.md, and vice versa.
Prompt guidance prevents overuse. Boolean gates should include behavioral guidance (e.g., "React sparingly") to prevent the model from always returning true.
File Map
File
Role
slack-respond/SKILL.md
Pipeline definition โ what Claude reads and follows
scripts/slack_format.py
XML tag definitions (COGNITIVE_INSTRUCTIONS) + extraction (cmd_extract)
scripts/slack_memory.py
Memory persistence โ user models, soul state, working memory