Jobgru on-demand — send LinkedIn connection invites with add-note text for user-named sheet rows; if already connected, send column H as a direct Message instead. Only Status applied; 2 people per row from Leads; appends Sent add note to column H after success (does not replace the note). Never runs in the Jobgru pipeline. Use when the user says SendGru, send add notes, send connection notes, or names rows to send invites.
Scanned 9/5/2026
Install to Claude Code
npx -y skills add ashujha301/jobgru --skill sendgru --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Sendgru?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/ashujha301-sendgru)More formats (shields.io, HTML) on the badges page.
---
name: sendgru
description: Jobgru on-demand — send LinkedIn connection invites with add-note text for user-named sheet rows; if already connected, send column H as a direct Message instead. Only Status applied; 2 people per row from Leads; appends Sent add note to column H after success (does not replace the note). Never runs in the Jobgru pipeline. Use when the user says SendGru, send add notes, send connection notes, or names rows to send invites.
---
# SendGru (on-demand connection + note)
Send LinkedIn **Connect → Add a note → Send** for rows the user names. **Never** runs automatically after Jobgru or LeadGru.
LeadGru is unchanged: it still finds **5 people + company people page** on `to apply` rows. SendGru only sends to **2** of those people so you cover more companies per week.
## Hard rules
| Rule | Value |
| --- | --- |
| Trigger | User must name rows (`4-12`, `8`, `4,6,9`) or say SendGru / send add notes |
| Pipeline | **Never** part of Jobgru Phase 1/2/2b |
| Status filter | **applied** only (case-insensitive) |
| People per row | **2** — first two `/in/` URLs in column G; skip `Company:` line |
| Note source | Column H **before** send (LeadGru template text) |
| Note length | **1–300** characters (Premium desktop). Skip if empty or over 300 |
| After success | **Append** ` Sent add note` to the existing H text (same cell; do not replace) |
| Already sent | Skip if H already contains `Sent add note` |
| Sheet writes | **Sheets API only** — never browser-type into the sheet |
| LinkedIn tabs | **One** tab |
| Daily cap | **20** sends per run (use `--apply-daily-cap` on select script) |
| Stop | CAPTCHA, checkpoint, weekly invitation limit → unlock, report partial, **no retries this session** |
## Prerequisites
```bash
.venv/bin/python scripts/jobgru_check.py --json
```
- LinkedIn logged in (Premium: connection notes up to **300** characters)
- Rows must have Leads (G) filled (usually from LeadGru) and Add note Message (H) from templates
- User must have set Status to **applied** after applying to the job
## Browser fallback ladder (mandatory — do not stop at MCP error)
SendGru **requires a live browser**. If one path fails, try the next **before** reporting blocked.
| Priority | Method | When |
| --- | --- | --- |
| 1 | **Cursor Browser MCP** (`cursor-ide-browser`) | Default in Cursor — `browser_navigate`, `browser_snapshot`, `browser_click`, … |
| 2 | **Playwright MCP** | If registered — discover via MCP tool list (`playwright`, `browser_navigate`, …) |
| 3 | **Playwright CLI (no MCP)** | **Always try this if MCP is disconnected** — works in Cursor without reload |
### Fallback 3 — Playwright CLI (recommended when MCP fails)
```bash
.venv/bin/python scripts/sendgru_select.py --rows "64-70" --apply-daily-cap
.venv/bin/python scripts/sendgru_playwright.py --rows "64-70" --apply-daily-cap
```
Uses `~/.jobgru/browser-profile` (same cookies as `jobgru mcp login`). **One-time login:**
```bash
jobgru mcp login
```
Sign into LinkedIn in the opened browser, press ENTER in terminal.
**Do not** tell the user to reload Cursor as the only fix — run the Playwright CLI first. Reload MCP only if CLI also fails or user prefers MCP pacing/UI.
Dry-run (select only, no browser):
```bash
.venv/bin/python scripts/sendgru_playwright.py --rows "64-70" --apply-daily-cap --dry-run
```
---
## Coordinator workflow
### 1 — Parse rows and load sheet
```bash
.venv/bin/python scripts/sendgru_select.py --rows "4-12" --apply-daily-cap
```
Or read manually:
```bash
.venv/bin/python scripts/sheets_write.py read --range "A4:H12"
```
Use [`scripts/sendgru_select.py`](../../scripts/sendgru_select.py) JSON output: `actionable` vs `skipped`.
### 2 — Browser lock
1. `browser_tabs` list
2. If LinkedIn tab exists: `browser_lock` lock first
3. Else: `browser_navigate` to first profile URL, then lock
Read runbook: [`data/linkedin-runbooks/connect-add-note.json`](../../data/linkedin-runbooks/connect-add-note.json)
### 3 — Per person (max 2 per row)
**Before each profile navigate after the first:** blocking sleep **60–90 seconds** (randomize in range; do not batch).
Follow runbook steps in order:
1. Navigate to `/in/` URL
2. Snapshot — if page shows stop phrases (see runbook `stop_phrases`), **stop session**
3. If **Pending** — skip person, continue
4. If **Message** only (already 1st-degree connected, no Connect) — click **Message**, paste exact column H text, click **Send**
5. If **Connect** fails to open the invite modal but **Message** is available — use **Message** (direct DM) with the same note text
6. Otherwise **Connect** (fixed two-path flow — do not guess):
- **Path A:** Blue **Connect** in profile header → click it
- **Path B:** No Connect, but **Follow** is shown → click **More** (grey button **beside** Follow/Message in the profile header — **not** the sidebar “More profiles for you”) → **Connect** in that dropdown
- Modal opens with **Add a note** and **Send without a note**
7. Click **Add a note** (if missing, skip person — do not use “Send without a note”)
8. Paste **exact** column H text (`browser_fill` or type)
9. Click **Send** / **Send invitation**
10. Wait **5s**, snapshot to confirm dialog closed
**Between companies** (after finishing a row’s people): extra **30s** before next row’s first profile.
### 4 — Mark row done
After finishing a row (sent 1–2 people successfully on that row), **append** `Sent add note` to the existing H text. Never replace the note.
```bash
.venv/bin/python scripts/sendgru_select.py --rows "{ROW}" --mark-sent
```
- Mark row **only** if at least one invite or direct message sent successfully for that row
- If both people skipped (pending only — not already connected), **do not** append `Sent add note` — report row
- If session stopped mid-row due to rate limit, **do not** mark partial rows unless user confirms
- Do **not** `sheets_write.py write --value "Sent add note"` — that wipes the template text
### 5 — Unlock and report
```bash
browser_lock action unlock
```
Save summary to `data/runs/sendgru-<YYYY-MM-DD-HHMM>.json`:
```json
{
"mode": "sendgru",
"rows_requested": [4, 5, 6],
"rows_sent": [4, 5],
"rows_skipped": [{"row": 6, "reason": "already Sent add note"}],
"people_sent": 4,
"stopped_reason": null
}
```
## Column reference
| Column | Header | SendGru |
| --- | --- | --- |
| A | Company Name | Read |
| B | Position | Read |
| D | Status | Must be **applied** |
| G | Leads | Read — first **2** `/in/` only |
| H | Add note Message | Read note to send → **append** ` Sent add note` after send |
## What not to do
- Do not run after every job search
- Do not send to 5 people per company (LeadGru bench stays on sheet; you send 2)
- Do not send if H is empty or over **300** chars (Premium limit)
- Do not replace H with only `Sent add note` — always append to the existing text
- Do not append `Sent add note` if zero invites sent on that row
- Do not use InMail
- Do not parallel LinkedIn tabs
- Do not retry after CAPTCHA / weekly limit in the same session
- Do not type into Google Sheet in the browser
## LinkedIn limits (Premium)
LinkedIn does not publish exact weekly invite counts. Observed safe band: **~100–200 invites / rolling 7 days**. This skill defaults to **20 sends/run** and **60–90s** between people to reduce restriction risk. **Cannot guarantee** zero rate limits.
Connection note on desktop Premium: up to **300** characters. SendGru skips only if H is empty or over 300. LeadGru still writes new H notes at **≤ 200** from sheet templates.
## Standalone prompt
Copy from [`prompts/sendgru-run.md`](../../prompts/sendgru-run.md).
## Test order
1. Unit tests: `python -m unittest tests.test_sendgru_select`
2. Dry run: `sendgru_select.py --rows "N"` — confirm actionable/skipped
3. Live: **one** applied row (2 sends max), then re-run → row skipped (H contains `Sent add note`)
4. Larger ranges only after a clean single-row test
## Related skills
| Skill | Relationship |
| --- | --- |
| [leadgru/SKILL.md](../leadgru/SKILL.md) | Finds 5 people + note template — **does not send** |
| [jobgru/SKILL.md](../jobgru/SKILL.md) | Pipeline — **does not send invites** |
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!