bereach-openclaw 0.2.16 → 0.2.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
package/skills/bereach/SKILL.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: bereach
|
|
3
3
|
description: "Automate LinkedIn outreach via BeReach (berea.ch). Use when: prospecting, engaging posts, scraping engagement, searching LinkedIn, managing inbox, running campaigns, managing invitations. Requires BEREACH_API_KEY."
|
|
4
|
-
lastUpdatedAt:
|
|
4
|
+
lastUpdatedAt: 1772678140
|
|
5
5
|
metadata: { "openclaw": { "requires": { "env": ["BEREACH_API_KEY"] }, "primaryEnv": "BEREACH_API_KEY" } }
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -17,7 +17,7 @@ Automate LinkedIn prospection and engagement via BeReach.
|
|
|
17
17
|
|
|
18
18
|
| Sub-skill | Keywords | URL | lastUpdatedAt |
|
|
19
19
|
| --------------------- | ------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ------------- |
|
|
20
|
-
| Lead Magnet | lead magnet, comment to DM, resource delivery, post giveaway, auto-accept invitations, scheduled run, recap, campaign stats, pause | sub/lead-magnet.md |
|
|
20
|
+
| Lead Magnet | lead magnet, comment to DM, resource delivery, post giveaway, auto-accept invitations, scheduled run, recap, campaign stats, pause | sub/lead-magnet.md | 1772678140 |
|
|
21
21
|
| OpenClaw Optimization | openclaw, model, opus, sonnet, haiku, config, SOUL.md, heartbeat, prompt caching, AI cost reduction, /model | openclaw-optimization.md | 1772619338 |
|
|
22
22
|
| SDK Reference | sdk, method, parameter, signature, reference, api, script | sdk-reference.md | 1772672714 |
|
|
23
23
|
|
|
@@ -81,9 +81,13 @@ The SDK auto-reads `BEREACH_API_KEY` from the environment. NEVER hardcode tokens
|
|
|
81
81
|
|
|
82
82
|
- Lead magnet scripts use the SDK. Tools are for interactive agent use only.
|
|
83
83
|
- Import from the `bereach` SDK exclusively. If a method doesn't exist, the operation doesn't exist.
|
|
84
|
-
- Scripts MUST be TypeScript (`.ts`).
|
|
85
|
-
|
|
86
|
-
|
|
84
|
+
- Scripts MUST be TypeScript (`.ts`). Load the [SDK Reference](sdk-reference.md) sub-skill for method signatures.
|
|
85
|
+
|
|
86
|
+
**Mandatory validation loop** — after generating or editing any script:
|
|
87
|
+
|
|
88
|
+
1. Run `npx tsc --noEmit` in the script directory. If type errors: fix them using the SDK Reference, then repeat.
|
|
89
|
+
2. Run `npx tsx <script-name>.ts` — fix runtime errors (e.g. "linkedinInbox is not defined", "visitProfile is not a function"). If config missing, run with minimal env to reach first SDK call.
|
|
90
|
+
3. Only after both pass: consider the script ready.
|
|
87
91
|
|
|
88
92
|
### Always
|
|
89
93
|
|
|
@@ -139,7 +143,7 @@ More workflows coming soon. You can build your own using the SDK methods and too
|
|
|
139
143
|
|
|
140
144
|
Crons are OpenClaw scheduled tasks. Create entries in `~/.openclaw/cron/jobs.json` (via `openclaw cron add`).
|
|
141
145
|
|
|
142
|
-
**Lead Magnet** — 3 global crons.
|
|
146
|
+
**Lead Magnet** — 3 global crons. Campaign config at `~/.bereach/lead-magnet.json`. Each cron runs one script that loops over all enabled campaigns:
|
|
143
147
|
|
|
144
148
|
```json
|
|
145
149
|
{ "id": "lm-comments", "every": "1h", "skill": "bereach", "sessionTarget": "spawn", "prompt": "Run lm-comments.ts and report recap" }
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: bereach-lead-magnet
|
|
3
3
|
description: "Lead magnet workflow — deliver a resource to everyone who engages with a LinkedIn post."
|
|
4
|
-
lastUpdatedAt:
|
|
4
|
+
lastUpdatedAt: 1772678140
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# BeReach Lead Magnet Skill
|
|
@@ -16,6 +16,14 @@ Requires [BeReach SKILL.md](SKILL.md) (constraints, SDK setup, anti-hallucinatio
|
|
|
16
16
|
|
|
17
17
|
All lead magnet scripts MUST be TypeScript using the `bereach` SDK (see main skill for SDK setup and rules).
|
|
18
18
|
|
|
19
|
+
**Always use full SDK paths** — e.g. `client.linkedinChat.findConversation`, `client.linkedinScrapers.visitProfile`. Never infer the resource from method name alone (e.g. "inbox" ≠ linkedinInbox; "visit" ≠ linkedinActions.visitProfile).
|
|
20
|
+
|
|
21
|
+
**Validation loop (mandatory)** — after writing each script:
|
|
22
|
+
|
|
23
|
+
1. `npx tsc --noEmit` — fix any type errors using SDK Reference.
|
|
24
|
+
2. `npx tsx <script-name>.ts` — fix any runtime errors (e.g. undefined method, wrong resource). If config is missing, run with minimal env to at least reach the first SDK call.
|
|
25
|
+
3. Repeat until both pass. Only then save or paste the script.
|
|
26
|
+
|
|
19
27
|
## Tone
|
|
20
28
|
|
|
21
29
|
All script output and chatbot messages are **for the end user**. Write like you're talking to a non-technical person. Never mention internal concepts like "Track A", "Layer 2", "DM guard", "server-side dedup", "retryAfter", "URN", "O(1) lookup", etc. The campaign slug is fine to show — it helps the user know which campaign is running. Just say what happened in plain language: "Sent the resource to 12 people", "Skipped 3 (already received it)", "Outside active hours, will resume at 7:00".
|
|
@@ -129,7 +137,7 @@ For each campaign (from config): scrape commenters and engage them.
|
|
|
129
137
|
2. **Fetch**: `collectComments` with `campaignSlug` → response: `profiles[]` (NOT "comments"). Paginate: while `hasMore`, increment `start` by `count`.
|
|
130
138
|
3. Each profile has: `profileUrl`, `commentUrn`, `name`, `profileUrn`, `actionsCompleted: { message, reply, like, visit, connect }`, `knownDistance`, `hasReplyFromPostAuthor`
|
|
131
139
|
4. For each profile (skip own URN, skip `actionsCompleted.message === true`):
|
|
132
|
-
a. If `knownDistance` is set, use it (skip visit, saves 1 credit). Otherwise: `visitProfile` with `campaignSlug` → `memberDistance`, `pendingConnection`
|
|
140
|
+
a. If `knownDistance` is set, use it (skip visit, saves 1 credit). Otherwise: `client.linkedinScrapers.visitProfile` with `{ profile, campaignSlug }` → `memberDistance`, `pendingConnection`
|
|
133
141
|
b. Distance 1:
|
|
134
142
|
- **DM dedup** (see "DM dedup" section): check both layers. If either says "already sent", skip. Otherwise: `sendMessage` with `campaignSlug`.
|
|
135
143
|
- Skip reply if `actionsCompleted.reply === true` or `hasReplyFromPostAuthor === true`. Otherwise: `replyToComment` with `commentUrn` and `campaignSlug`
|
|
@@ -147,7 +155,7 @@ Accept pending invitations and deliver the resource to campaign-related invitees
|
|
|
147
155
|
- **Campaign attribution**: `listInvitations` returns ALL pending invitations. Cross-reference each inviter against campaign commenter lists to find which campaign (if any) they belong to. Accept all invitations, but only DM if campaign-matched.
|
|
148
156
|
- For each invitation:
|
|
149
157
|
1. `acceptInvitation` with `invitationId` and `sharedSecret`
|
|
150
|
-
2. If campaign matched: `visitProfile` with
|
|
158
|
+
2. If campaign matched: `client.linkedinScrapers.visitProfile` with `{ profile, campaignSlug }`, then **DM dedup** → DM if not already sent.
|
|
151
159
|
3. If no campaign match (organic invitation): accept only, no DM.
|
|
152
160
|
|
|
153
161
|
### Script 3 — New connections
|
|
@@ -156,7 +164,7 @@ For each campaign (from config): check if distance 2+ commenters have now connec
|
|
|
156
164
|
|
|
157
165
|
- Re-fetch commenters: `collectComments` with `campaignSlug` — paginate all
|
|
158
166
|
- Filter: `actionsCompleted.message === false` and `knownDistance > 1` (skip profiles where `knownDistance` is null — they haven't been visited yet and belong to Script 1)
|
|
159
|
-
- For each: `visitProfile` with `campaignSlug` → check `memberDistance` and `pendingConnection`
|
|
167
|
+
- For each: `client.linkedinScrapers.visitProfile` with `{ profile, campaignSlug }` → check `memberDistance` and `pendingConnection`
|
|
160
168
|
- `memberDistance === 1`: **DM dedup** (see "DM dedup" section) → DM the resource if not already sent.
|
|
161
169
|
- `pendingConnection === "pending"`: not connected yet, skip
|
|
162
170
|
|
|
@@ -172,7 +180,7 @@ Check in order. If either says "already sent", skip the DM.
|
|
|
172
180
|
|
|
173
181
|
**Layer 1 — `actionsCompleted.message`** (free, within campaign). Already checked in the script loop — `true` → skip.
|
|
174
182
|
|
|
175
|
-
**Layer 2 —
|
|
183
|
+
**Layer 2 — DM guard** (0 credits, cross-campaign). Only when `resourceLink` is set. Call `client.linkedinChat.findConversation` with `{ profile, includeMessages: true }` → `{ found, messages }`. `messages` is at the **top level**, not nested. If any message text contains `resourceLink`: skip DM, call `client.campaigns.syncActions` to mark done. If found but no link in messages: pass `messages` as context for DM tone adaptation. The function must return both skip decision and messages.
|
|
176
184
|
|
|
177
185
|
**Fail-safe**: if `findConversation` errors or all retries fail, **skip this profile** — do NOT send the DM. A failed lookup treated as "not found" causes duplicates. The profile will be retried next run.
|
|
178
186
|
|
|
@@ -206,7 +214,7 @@ Follow pacing rules from the main skill (Constraints #2). No exceptions — slee
|
|
|
206
214
|
|
|
207
215
|
## Cron
|
|
208
216
|
|
|
209
|
-
Three global crons.
|
|
217
|
+
Three global crons. Campaign config at `~/.bereach/lead-magnet.json`. Each cron runs one script that loops over all enabled campaigns.
|
|
210
218
|
|
|
211
219
|
All crons MUST use `"sessionTarget": "spawn"` to avoid blocking the main session. Each spawned sub-agent runs the script independently and pushes the recap back to the user when done.
|
|
212
220
|
|