npx claudepluginhub kinginyellows/yellow-plugins --plugin yellow-devinWant just this command?
Add to a custom plugin, then install with one command.
Send a follow-up message to an active Devin session. Use when user wants to give Devin additional context, says "tell Devin to...", "update Devin", or "send message to session".
<session-id> <message>devin/Send Message to Devin Session
Send a follow-up message to provide additional context, instructions, or course corrections to a Devin session.
Workflow
Step 1: Validate Prerequisites
Validate DEVIN_SERVICE_USER_TOKEN and DEVIN_ORG_ID are set. Check jq is
available. See devin-workflows skill for validation functions.
Step 2: Parse Arguments
Parse $ARGUMENTS:
- First token is the session ID
- Remaining text is the message
If session ID or message is missing, prompt via AskUserQuestion.
Step 3: Validate Inputs
- Session ID: Validate with
validate_session_idfromdevin-workflowsskill —^[a-zA-Z0-9_-]{8,64}$ - Message: Max 2000 characters. On overflow, report actual count vs maximum — never truncate.
Step 4: Verify Session State (C1 Validation)
Fetch session status using the org-scoped list endpoint with session_ids
filter (see Session Lookup Pattern in devin-workflows skill):
DEVIN_API_BASE="https://api.devin.ai/v3"
ORG_URL="${DEVIN_API_BASE}/organizations/${DEVIN_ORG_ID}"
response=$(curl -s --connect-timeout 5 --max-time 10 \
-w "\n%{http_code}" \
-X GET "${ORG_URL}/sessions?session_ids=${SESSION_ID}&first=1" \
-H "Authorization: Bearer $DEVIN_SERVICE_USER_TOKEN")
Parse from items array: jq '.items[0]'. If the result is null or the array
is empty, report "Session not found."
Check session status against messageable states:
Messageable states:
running— proceed normallysuspended— inform user: "Session is suspended. Sending a message will auto-resume it." Then proceed.
Not messageable:
resuming— report: "Session is resuming. Wait a moment and try again, or use/devin:status {id}to check."new,claimed— report: "Session is {status} — waiting to start. Try again shortly or use/devin:statusto monitor."exit,error(terminal) — report: "Session is {status} — cannot send messages to a completed session."
Step 5: Send Message
Construct JSON via jq and POST. Try the org-scoped endpoint first (requires
ManageOrgSessions); if it returns 403, fall back to the enterprise endpoint
(requires ManageAccountSessions):
# Try org-scoped endpoint first
response=$(jq -n --arg msg "$MESSAGE" '{message: $msg}' | \
curl -s --connect-timeout 5 --max-time 30 \
-w "\n%{http_code}" \
-X POST "${ORG_URL}/sessions/${SESSION_ID}/messages" \
-H "Authorization: Bearer $DEVIN_SERVICE_USER_TOKEN" \
-H "Content-Type: application/json" \
-d @-)
curl_exit=$?
http_status=${response##*$'\n'}
body=${response%$'\n'*}
# Fall back to enterprise endpoint on 403
if [ "$curl_exit" -eq 0 ] && [ "$http_status" = "403" ]; then
printf 'WARN: Org-scoped message endpoint returned 403, trying enterprise scope...\n' >&2
ENTERPRISE_URL="${DEVIN_API_BASE}/enterprise"
response=$(jq -n --arg msg "$MESSAGE" '{message: $msg}' | \
curl -s --connect-timeout 5 --max-time 30 \
-w "\n%{http_code}" \
-X POST "${ENTERPRISE_URL}/sessions/${SESSION_ID}/messages" \
-H "Authorization: Bearer $DEVIN_SERVICE_USER_TOKEN" \
-H "Content-Type: application/json" \
-d @-)
curl_exit=$?
http_status=${response##*$'\n'}
body=${response%$'\n'*}
fi
Never use the message_as_user_id field — impersonation risk.
Check curl exit code, HTTP status, jq parse — see devin-workflows skill.
Step 5b: PR Comment Fallback (on 403)
If both org-scoped and enterprise endpoints returned 403, offer to post the message as a PR comment instead. Devin automatically responds to PR comments as long as the session is not archived.
-
Check
ghavailability inline:if ! command -v gh >/dev/null 2>&1; then printf 'gh CLI not found — PR comment fallback unavailable.\n' # Fall through to standard error reporting elif ! gh auth status >/dev/null 2>&1; then printf 'gh not authenticated — run `gh auth login` to enable PR comment fallback.\n' # Fall through to standard error reporting fiIf
ghis not available or not authenticated, skip the PR comment fallback and report the 403 error with a note to run/devin:setup. -
Detect current repo:
REPO_SLUG=$(gh repo view --json nameWithOwner -q .nameWithOwner 2>/dev/null || echo "")If
REPO_SLUGis empty, skip the PR comment fallback — cannot determine the current repo. -
Extract PRs from session data (already fetched in Step 4):
Parse
pull_requestsfrom the session response. Filter for PRs matching the current repo (REPO_SLUG). Extract PR number from the PR URL. -
Offer fallback via AskUserQuestion:
If matching PRs exist:
API message failed (403 — ManageOrgSessions may be missing). This session has PR #N in this repo. Devin monitors PR comments and will pick up instructions posted there. Options: - Comment on PR — Post as PR comment with @devin prefix - Run /devin:setup — Check and fix permissions - CancelIf no matching PRs: skip the fallback, show the 403 error with a note to run
/devin:setup. -
Post comment if chosen:
Check archived status first: If the session's
is_archivedfield is true, warn in the AskUserQuestion prompt: "Session {id} is archived — Devin will not respond to PR comments for archived sessions." Change the option label to "Comment on PR anyway — for documentation purposes".Compose with
@devinprefix first, then sanitize before posting (preventcog_andapk_token leakage):COMMENT_BODY="@devin ${MESSAGE}" SAFE_BODY=$(printf '%s' "$COMMENT_BODY" | sed 's/\(cog\|apk\)_[a-zA-Z0-9_-]*/***REDACTED***/g') gh pr comment "$PR_NUMBER" --repo "$REPO_SLUG" --body "$SAFE_BODY"@devinmust be at the very start of the comment body (prefix match for mention-only filtering). The comment posts as the authenticated GitHub user, which Devin responds to by default. The message is already bounded by the 2000-char input validation in Step 3, so no additional truncation is needed.Check the exit code of
gh pr comment. If non-zero, report the error: "Failed to post PR comment: {error}. Checkgh auth statusand repo permissions." Do not proceed to step 6. -
Report result (only on success): "Message posted as comment on PR #N. Devin will pick up the instructions automatically."
Step 6: Report
Display confirmation with updated session status from the response.
If the session was suspended and is now resuming:
- "Message sent. Session is resuming from suspended state."
- Suggest: "Use
/devin:status {id}to check when it's running."
Otherwise:
- "Message sent to session {id}."
- Show current status.
- Suggest: "Use
/devin:status {id}to check progress."
Error Handling
See devin-workflows skill for error handling patterns. All error output must
sanitize tokens.