---
name: exe-intercom
description: Receive dispatched task via tmux send-keys and begin working
allowed-tools: Bash
---

# Intercom — Task Dispatch Receiver

Triggered by the coordinator via `tmux send-keys -t {window} '/exe-intercom' Enter`. Scans the employee's task folder and starts working immediately if tasks exist.

```bash
# Resolve the configured coordinator and current tmux session.
COORDINATOR=$(node -e "const fs=require('fs'), os=require('os'), path=require('path'); try { const r=JSON.parse(fs.readFileSync(path.join(os.homedir(),'.exe-os','exe-employees.json'),'utf8')); const c=r.find(e => String(e.role||'').toLowerCase()==='coo'); console.log(c?.name || 'exe'); } catch { console.log('exe'); }" 2>/dev/null)

if [ -n "$EXE_SESSION_NAME" ]; then
  SESSION_NAME="$EXE_SESSION_NAME"
elif [ -n "$TMUX" ]; then
  SESSION_NAME=$(tmux display-message -p '#{session_name}' 2>/dev/null)
else
  SESSION_NAME="UNKNOWN"
fi

# Employee sessions are {employee}-{coordinatorSession}; coordinator sessions have no dash.
if [ "$SESSION_NAME" = "UNKNOWN" ]; then
  AGENT="UNKNOWN"
elif [[ "$SESSION_NAME" == *-* ]]; then
  AGENT=$(echo "${SESSION_NAME%%-*}" | sed -E 's/[0-9]+$//')
else
  AGENT="$COORDINATOR"
fi

# Skip if no agent
if [ "$AGENT" = "UNKNOWN" ] || [ "$AGENT" = "default" ]; then
  exit 0
fi

# FAST PATH: Check task signal files (no Node.js, no DB, <10ms).
# Signal files are written by create_task in two possible locations:
#   1. Session-scoped: task-signals/{session}/{agent}.{task-id}.pending
#   2. Legacy flat: task-signals/{agent}.pending
# Check BOTH paths. Session-scoped first (authoritative), then legacy.

# Derive session scope from tmux session name
if [[ "$SESSION_NAME" == *-* ]]; then
  SESSION_SCOPE="${SESSION_NAME##*-}"
else
  SESSION_SCOPE="$SESSION_NAME"
fi

# Check session-scoped signals: task-signals/{scope}/{agent}.*.pending
# Prioritize TASK signals over REVIEW signals. Pick newest file.
SCOPED_DIR="$HOME/.exe-os/task-signals/${SESSION_SCOPE}"
SIGNAL_FILE=""
if [ -d "$SCOPED_DIR" ]; then
  # Task signals first (not review-*), newest first
  SIGNAL_FILE=$(find "$SCOPED_DIR" -name "${AGENT}.*.pending" ! -name "${AGENT}.review-*" -type f 2>/dev/null | xargs ls -t 2>/dev/null | head -1)
  # Fall back to review signals if no task signals
  if [ -z "$SIGNAL_FILE" ]; then
    SIGNAL_FILE=$(find "$SCOPED_DIR" -name "${AGENT}.*.pending" -type f 2>/dev/null | xargs ls -t 2>/dev/null | head -1)
  fi
fi

# Fallback: check root task-signals/{agent}.*.pending (cross-session or old format)
if [ -z "$SIGNAL_FILE" ]; then
  SIGNAL_FILE=$(find "$HOME/.exe-os/task-signals" -maxdepth 1 -name "${AGENT}.*.pending" ! -name "${AGENT}.review-*" -type f 2>/dev/null | xargs ls -t 2>/dev/null | head -1)
fi

# Legacy fallback: {agent}.pending (no task ID suffix)
if [ -z "$SIGNAL_FILE" ]; then
  LEGACY_FILE="$HOME/.exe-os/task-signals/${AGENT}.pending"
  if [ -f "$LEGACY_FILE" ]; then
    SIGNAL_FILE="$LEGACY_FILE"
  fi
fi

if [ -n "$SIGNAL_FILE" ] && [ -f "$SIGNAL_FILE" ]; then
  SIGNAL=$(cat "$SIGNAL_FILE" 2>/dev/null)
  TITLE=$(echo "$SIGNAL" | node -e "try{const d=JSON.parse(require('fs').readFileSync(0,'utf8'));console.log(d.title)}catch{}" 2>/dev/null)
  PRIORITY=$(echo "$SIGNAL" | node -e "try{const d=JSON.parse(require('fs').readFileSync(0,'utf8'));console.log(d.priority)}catch{}" 2>/dev/null)
  TASK_ID=$(echo "$SIGNAL" | node -e "try{const d=JSON.parse(require('fs').readFileSync(0,'utf8'));console.log(d.task_id)}catch{}" 2>/dev/null)
  echo "MANDATORY: You have 1 unstarted task(s)."
  echo "Highest priority: ${TITLE} [${PRIORITY}]"
  echo ""
  echo "START WORKING NOW. Run get_task(task_id=\"${TASK_ID}\") and begin immediately."
  rm -f "$SIGNAL_FILE"
  exit 0
fi

# Full check — one Node process for all intercom queries (coordinator reviews, messages, notifications).
# Only runs if no signal file exists (signal file is the fast path for task dispatch).
if [ "$AGENT" = "$COORDINATOR" ] || [ "$AGENT" = "exe" ]; then
  EXE_SESSION="$SESSION_NAME" EXE_SESSION_NAME="$SESSION_NAME" node "$(npm root -g)/@askexenow/exe-os/dist/bin/intercom-check.js" "$AGENT" --coordinator 2>/dev/null
else
  EXE_SESSION="$SESSION_NAME" EXE_SESSION_NAME="$SESSION_NAME" node "$(npm root -g)/@askexenow/exe-os/dist/bin/intercom-check.js" "$AGENT" 2>/dev/null
fi
```

### For the coordinator
**If output shows `[REVIEW NOTIFICATIONS]` and you are idle (no active conversation):** start reviewing immediately. Run `/exe-review`. Do not ask the founder for permission.
**If output shows `[REVIEW NOTIFICATIONS]` and the founder is mid-conversation:** note them briefly and continue. Review after the current topic concludes.
**If output is empty:** no pending reviews — stay silent.

### For employees (all other agents)
**If output starts with "MANDATORY:"** — you are idle. Read the task file and begin working immediately. Do not ask what to do.
**If output starts with "Continue working on:"** — you are already busy. Finish your current task first. Task chaining will pick up the next task automatically.
**If output is empty:** no tasks — stay silent.

---

## Context-full intercom format

When an employee's context window fills, they send this intercom to the coordinator before stopping:

```
/exe-intercom context-full: <name> hit capacity. Checkpoint saved. Resume task <task-id>.
```

**What the coordinator does when it receives this:**
1. **Verify before killing.** Call `verifyPaneAtCapacity(sessionName)` from `src/lib/tmux-routing.ts`. It captures the last 200 lines of the employee's pane and runs the filtered capacity matcher.
   - If `atCapacity: false`: the intercom is a false positive (pane echo, rendered skill doc, RESUME banner matching the intercom syntax). Do NOT kill. Send a nudge via `tmux send-keys`: `"False context-full detected (reason: <result.reason>). Continue working. If intentional, explain trigger."` Report to founder and stop.
   - If `atCapacity: true`: proceed to step 2.
2. Kill the employee's session: `tmux kill-session -t <name>-<coordinator-session>`
3. Create or refresh a resume task via `resume_employee` (auto-dispatches a fresh session on first creation)
4. Report to founder

**What the employee does before sending this:**
1. `store_memory` with text starting `"CONTEXT CHECKPOINT [<task-id>]: ..."` — captures current state
2. Send the context-full intercom to the coordinator
3. Stop — do not continue working

**What the resumed session does on boot:**
1. `recall_my_memory("CONTEXT CHECKPOINT [<task-id>]")` — retrieves exact state
2. Continues from where the previous session stopped
