bereach-openclaw 1.2.0 → 1.3.2

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # BeReach — OpenClaw Plugin
2
2
 
3
- LinkedIn outreach automation via [BeReach](https://berea.ch). Registers 33 in-process tools and auto-reply commands.
3
+ LinkedIn outreach automation via [BeReach](https://berea.ch). Registers 60+ in-process tools and instant status commands.
4
4
 
5
5
  ## Install
6
6
 
@@ -137,11 +137,11 @@ They should match. Per [OpenClaw Plugin Manifest](https://docs.openclaw.ai/plugi
137
137
 
138
138
  ## Usage
139
139
 
140
- ### Tools (33 registered)
140
+ ### Tools (60+ registered)
141
141
 
142
142
  All BeReach operations are available as agent tools — the agent uses them automatically based on your requests. No MCP needed; tools run in-process via the `bereach` SDK.
143
143
 
144
- ### Auto-reply commands
144
+ ### Instant status commands
145
145
 
146
146
  These execute instantly without invoking the AI:
147
147
 
@@ -161,8 +161,8 @@ openclaw bereach status
161
161
 
162
162
  | Component | Description |
163
163
  | --- | --- |
164
- | `src/tools/` | 33 tool definitions generated from OpenAPI |
165
- | `src/commands/` | Auto-reply commands + CLI |
164
+ | `src/tools/` | 60+ tool definitions generated from OpenAPI |
165
+ | `src/commands/` | Instant status commands + CLI |
166
166
  | `skills/bereach/SKILL.md` | Main behavioral skill |
167
167
  | `skills/bereach/sub/lead-magnet.md` | Lead magnet workflow |
168
168
  | `skills/bereach/sdk-reference.md` | SDK method reference |
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "id": "bereach-openclaw",
3
3
  "name": "BeReach",
4
- "version": "1.2.0",
5
- "description": "LinkedIn outreach automation — 33 tools, auto-reply commands",
4
+ "version": "1.3.2",
5
+ "description": "LinkedIn outreach automation — 60+ tools, instant status commands",
6
6
  "configSchema": {
7
7
  "type": "object",
8
8
  "additionalProperties": false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bereach-openclaw",
3
- "version": "1.2.0",
3
+ "version": "1.3.2",
4
4
  "description": "BeReach LinkedIn automation plugin for OpenClaw",
5
5
  "license": "AGPL-3.0",
6
6
  "exports": {
@@ -15,12 +15,12 @@
15
15
  ]
16
16
  },
17
17
  "dependencies": {
18
- "bereach": "^1.2.3"
18
+ "bereach": "^1.3.2"
19
19
  },
20
20
  "devDependencies": {
21
- "@types/node": "^22.19.3",
21
+ "@types/node": "^25.5.0",
22
22
  "tsx": "^4.21.0",
23
23
  "typescript": "^5.9.3",
24
- "vitest": "^4.0.18"
24
+ "vitest": "^4.1.0"
25
25
  }
26
26
  }
@@ -1,10 +1,17 @@
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, analytics, company pages, Sales Navigator, content engagement, feed monitoring. Requires BEREACH_API_KEY."
4
- lastUpdatedAt: 1773274027
4
+ lastUpdatedAt: 1773675510
5
5
  metadata: { "openclaw": { "requires": { "env": ["BEREACH_API_KEY"] }, "primaryEnv": "BEREACH_API_KEY" } }
6
6
  ---
7
7
 
8
+ <!--
9
+ AUTO-GENERATED FILE — DO NOT EDIT
10
+ Source of truth: skills/ directory
11
+ Edit the source file, then run: pnpm build:plugins
12
+ Any direct edit to this file WILL be overwritten.
13
+ -->
14
+
8
15
  # BeReach — LinkedIn Outreach Automation
9
16
 
10
17
  Automate LinkedIn prospection and engagement via BeReach.
@@ -17,11 +24,22 @@ Automate LinkedIn prospection and engagement via BeReach.
17
24
 
18
25
  | Sub-skill | Keywords | URL | lastUpdatedAt |
19
26
  | --------------------- | ------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ------------- |
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 | 1773267546 |
21
- | Lead Gen | lead gen, find leads, search, qualify, ICP, pipeline, build list, scrape engagement, competitor, grow database, prospecting, hashtag, Sales Navigator | sub/lead-gen.md | 1773269560 |
22
- | Outreach | outreach, connect, DM, message, follow up, sequence, connection request, reply, personalized outreach, campaign outreach, warming, follow, like post | sub/outreach.md | 1773269560 |
27
+ | Lead Magnet | lead magnet, comment to DM, resource delivery, post giveaway, auto-accept invitations, scheduled run, recap, campaign stats, pause | sub/lead-magnet.md | 1773675510 |
28
+ | Lead Gen | lead gen, find leads, search, qualify, ICP, pipeline, build list, scrape engagement, competitor, grow database, prospecting, hashtag, Sales Navigator | sub/lead-gen.md | 1773663610 |
29
+ | Outreach | outreach, connect, DM, message, follow up, sequence, connection request, reply, personalized outreach, campaign outreach, warming, follow, like post | sub/outreach.md | 1773616752 |
23
30
  | OpenClaw Optimization | openclaw, model, opus, sonnet, haiku, config, SOUL.md, heartbeat, prompt caching, AI cost reduction, /model | openclaw-optimization.md | 1773274027 |
24
- | SDK Reference | sdk, method, parameter, signature, reference, api, script | sdk-reference.md | 1773269560 |
31
+ | SDK Reference | sdk, method, parameter, signature, reference, api, script | sdk-reference.md | 1773665416 |
32
+
33
+ ### Workspace Templates
34
+
35
+ At install or upgrade, set up the workspace with these templates:
36
+
37
+ | Template | Purpose | URL |
38
+ | --- | --- | --- |
39
+ | SOUL.md | Always-loaded tool listing + session startup + sub-skills routing table | workspace/soul-template.md |
40
+ | AGENTS.md | Lean sub-agent safety net | workspace/agents-template.md |
41
+
42
+ **Step 0 (mandatory at install/upgrade):** Check if SOUL.md contains `<!-- bereach-workspace-v`. If missing: fetch soul-template.md from the URL above (or via `GET /api/onboarding/soul`), write it into the user's SOUL.md between the markers. Set up the pipeline cron (every 15min) if not already configured. This step cannot be skipped.
25
43
 
26
44
  ### Supporting files
27
45
 
@@ -72,14 +90,15 @@ The SDK auto-reads `BEREACH_API_KEY` from the environment. NEVER hardcode tokens
72
90
  1. **Token** — read `BEREACH_API_KEY` from environment with no default/fallback value. If not set, stop immediately.
73
91
  2. **Read all sub-skills** — fetch every sub-skill listed above.
74
92
  3. **Context acquisition** — build a rich picture of the user before any workflow. This context feeds all sub-skills and makes the agent smarter from the start.
75
- - **Profile + language** — `getLinkedInProfile` (0 credits). Detect language from location, headline, posts. This becomes the default for all generated content.
93
+ - **Profile + language** — `profile.get` (0 credits). Detect language from location, headline, posts. This becomes the default for all generated content.
76
94
  - **Recent posts** — `getPosts({ count: 10 })` (0 credits). What topics resonate, tone, offer, engagement patterns.
77
95
  - **Followers** — `getFollowers({ count: 50 })` (1 credit/page). Reveals audience type; followers are warm leads already.
78
96
  - **Website** — if the profile contains a website URL, fetch and extract: what they sell, who they target, positioning.
79
97
  - **Documents/data** — if the user has provided files (ICP docs, prospect lists, CRM exports, target account lists), read them. No format requirement.
80
98
  - **Existing campaigns** — `getStats` per known campaign (0 credits). What's running, what worked, conversions.
81
- - **Lead-gen state** — `contacts.listCampaigns({ type: "lead_gen" })` (0 credits) to see existing lead-gen campaigns. `agentState.get("lead-gen")` (0 credits) to load previous state (angles, watchlist, learning data). If state exists, the agent resumes where it left off.
82
- - **Analytics** — `linkedinAnalytics.getFollowerAnalytics()` (1 credit). Follower demographics and growth trends. `linkedinAnalytics.getProfileViews()` (1 credit). Who's viewing the profile warm leads.
99
+ - **Memory discovery** — `agentState.list({ keysOnly: true })` (0 credits). Returns all stored state keys and timestamps. Use this to discover what the agent remembers from previous sessions — lead-gen state, outreach state, user profile, campaign configs. Load relevant keys with `agentState.get(key)`. Prefer this over hardcoded key names.
100
+ - **Lead-gen state** — `contacts.listCampaigns({ type: "lead_gen" })` (0 credits) to see existing lead-gen campaigns. If `agentState.list` returned a `lead-gen` key, load it with `agentState.get("lead-gen")` (0 credits) to resume where the agent left off.
101
+ - **Analytics** — `profile.getFollowerAnalytics()` (1 credit). Follower demographics and growth trends. `profile.getProfileViews()` (1 credit). Who's viewing the profile — warm leads.
83
102
  - **Company pages** — `companyPages.list()` (1 credit). If the user administers company pages, discover them for company-level posting and analytics.
84
103
  - **Competitors** — infer from industry, profile, and posts. Note competitor names and profile URLs for the engagement watchlist.
85
104
  4. **Welcome** — personalized welcome using profile data and context. Suggest a first action based on their profile, posts, and industry.
@@ -109,25 +128,31 @@ The SDK auto-reads `BEREACH_API_KEY` from the environment. NEVER hardcode tokens
109
128
 
110
129
  - NEVER hardcode tokens. Read from `process.env.BEREACH_API_KEY`. If not set, exit immediately.
111
130
  - NEVER invent a tool/method name. Check the resources table below or tool schemas.
131
+ - Profile inputs: URL, URN, or bare vanity name (e.g. `john-doe`).
112
132
  - If unsure about a method: check the SDK Reference sub-skill.
113
133
 
114
134
  ### SDK resources and methods
115
135
 
116
136
  | Resource | Methods |
117
137
  | --- | --- |
118
- | `client.linkedinScrapers` | `collectLikes`, `collectComments`, `collectCommentReplies`, `collectPosts`, `visitProfile`, `visitCompany`, `collectHashtagPosts`, `collectSavedPosts` |
119
- | `client.linkedinActions` | `connectProfile`, `listInvitations`, `acceptInvitation`, `sendMessage`, `replyToComment`, `likeComment`, `publishPost`, `commentOnPost`, `likePost`, `unlikePost`, `unlikeComment`, `editComment`, `editPost`, `repostPost`, `savePost`, `unsavePost`, `followProfile`, `unfollowProfile`, `followCompany`, `unfollowCompany`, `declineInvitation`, `withdrawInvitation`, `listSentInvitations` |
120
- | `client.linkedinChat` | `listConversations`, `searchConversations`, `findConversation`, `getMessages`, `archiveConversation`, `unarchiveConversation`, `starConversation`, `unstarConversation`, `listArchivedConversations`, `listStarredConversations`, `markAllRead`, `markSeen`, `reactToMessage`, `unreactToMessage`, `getUnreadCount`, `sendTypingIndicator` |
121
- | `client.linkedinSearch` | `unifiedSearch`, `searchPosts`, `searchPeople`, `searchCompanies`, `searchJobs`, `searchByUrl`, `resolveParameters` |
122
- | `client.profile` | `getLinkedInProfile`, `refresh`, `getPosts`, `getFollowers`, `getLimits`, `getCredits`, `listAccounts`, `updateAccount`, `getActivity`, `revalidate` |
123
- | `client.campaigns` | `getStatus`, `syncActions`, `getStats` |
124
- | `client.contacts` | `createCampaign`, `listCampaigns`, `addContacts`, `listContacts`, `updateContact`, `searchContacts`, `getStats`, `logActivity`, `getActivities` |
125
- | `client.linkedinAnalytics` | `getFollowerAnalytics`, `getPostAnalytics`, `getProfileViews`, `getSearchAppearances` |
126
- | `client.linkedinFeed` | `getFeed` |
127
- | `client.salesNavigator` | `search`, `searchPeople`, `searchCompanies` |
128
- | `client.companyPages` | `list`, `getAnalytics`, `getPermissions`, `getPosts` |
129
- | `client.settings` | `getDmPolling`, `updateDmPolling` |
130
- | `client.agentState` | `get`, `set` |
138
+ | `client.scrapers` | `collectPosts`, `visitProfile` |
139
+ | `client.linkedinScrapers` | `collectLikes`, `collectComments`, `visitCompany`, `listSavedPosts`, `collectHashtagPosts` |
140
+ | `client.linkedInScrapers` | `collectCommentReplies`, `getFeed` |
141
+ | `client.linkedInSearch` | `search`, `searchCompanies`, `resolveParameters` |
142
+ | `client.linkedinSearch` | `searchPosts`, `searchPeople`, `searchJobs`, `searchByUrl` |
143
+ | `client.actions` | `connectProfile`, `sendMessage`, `listSentInvitations`, `followCompany` |
144
+ | `client.linkedinActions` | `listInvitations`, `acceptInvitation`, `replyToComment`, `likePost`, `withdrawInvitation`, `followProfile`, `editPost`, `editComment`, `repostPost`, `unlikePost`, `unlikeComment`, `unsavePost`, `unfollowCompany` |
145
+ | `client.linkedInActions` | `likeComment`, `publishPost`, `createComment`, `declineInvitation`, `unfollowProfile`, `savePost` |
146
+ | `client.profile` | `get`, `listAccounts`, `updateAccount`, `refresh`, `getPosts`, `getFollowers`, `getLimits`, `getCredits`, `getProfileViews`, `getSearchAppearances`, `getPostAnalytics`, `getFollowerAnalytics` |
147
+ | `client.companyPages` | `list`, `getPosts`, `getPermissions`, `getAnalytics` |
148
+ | `client.linkedinChat` | `listInboxConversations`, `getMessages`, `markAllRead`, `listArchived`, `react`, `sendTypingIndicator`, `getUnreadCount` |
149
+ | `client.chat` | `searchConversations`, `findConversation`, `archive`, `unreact` |
150
+ | `client.linkedInChat` | `markSeen`, `star`, `unstar`, `listStarred`, `unarchive` |
151
+ | `client.campaigns` | `getStatus`, `sync`, `getStats` |
152
+ | `client.contacts` | `upsert` |
153
+ | `client.salesNavigatorSearch` | `search`, `searchCompanies` |
154
+ | `client.salesNav` | `searchPeople` |
155
+ | **API-only (REST)** | `contacts.*` (campaigns, addContacts, updateContact, searchContacts, etc.), `agentState.*`, `settings.*` — use tools or REST API, not SDK |
131
156
 
132
157
  ## Tone
133
158
 
@@ -139,10 +164,10 @@ These are technical constraints BeReach requires. Everything else, adapt as need
139
164
 
140
165
  1. **Dedup** — pass `campaignSlug` on every action. BeReach deduplicates by target automatically. Duplicates return `duplicate: true` and cost nothing. Pre-check: use `client.campaigns.getStatus()` or the `getStatus` tool.
141
166
  2. **Pacing** — after every SDK/tool call, sleep a random delay. Write actions (DM, reply, like, comment, connect, accept, follow, repost, edit, sync): `random delay 8-12s`. Read actions (visit, scrape, search, find, feed, analytics, count-0 checks): `random delay 2-6s`. Inbox management (archive, star, mark-read, react, typing): `random delay 1-3s`. On 429: wait the number of seconds from the error response, retry (max 3). If daily/weekly cap hit, switch action type.
142
- 3. **Save incrementally** — persist tracking after each action, not at the end.
167
+ 3. **Save incrementally** — persist pipeline progress and tracking state after each action, not at the end. Contact data is auto-saved by API calls; only save operational state (e.g. which posts were scraped, discovery sources processed).
143
168
  4. **Limits check** — call `getLimits` once per day at session start.
144
169
  5. **Visit before connecting** — looks natural to LinkedIn.
145
- 6. **Credits** — check with `getCredits` → `{credits: {current, limit, remaining, percentage}}`.
170
+ 6. **Credits** — check with `getCredits` → `{credits: {current, limit, remaining, percentage, isUnlimited}}`. When `isUnlimited` is true, `remaining` and `limit` are null — credits are unlimited, skip credit budgeting.
146
171
  7. **Connection requests are scarce** — only 30/day. Before sending one, check `pendingConnection` from the visit response: `"pending"` = already sent, skip. `"failed"` = failed today, skip. `"none"` = safe to send.
147
172
  8. **Error handling** — wrap every SDK call in a shared helper. The wrapper must check the **error type** to branch:
148
173
  - `429`: wait `error.retryAfter` seconds, retry (max 3). All retries fail → skip profile, move on.
@@ -153,47 +178,152 @@ These are technical constraints BeReach requires. Everything else, adapt as need
153
178
  - Parse the response body inside a try/catch — malformed JSON must not crash the script.
154
179
  - Never treat a failed call as "success with empty result".
155
180
  - Never `process.exit()` on transient errors — skip and continue.
181
+ 9. **Stage transitions** — lifecycle stages are forward-only: `contact` → `lead` → `qualified` → `approved`. The only exception is `rejected`, which can be set from any stage. Downgrade attempts are silently ignored by the API.
182
+
183
+ ## Platform Infrastructure
184
+
185
+ These systems run automatically. The agent should rely on them, not replicate their work.
186
+
187
+ ### Auto-Upsert from Activity
188
+
189
+ When the agent scrapes posts, reads inbox, or finds a conversation, BeReach auto-creates contacts in the CRM for every LinkedIn profile encountered. The agent does NOT need to manually upsert after every scrape.
190
+
191
+ The agent should still:
192
+
193
+ - Update `lifecycleStage`, `hotScore`, `qualificationNotes` on contacts it qualifies
194
+ - Add contacts to campaigns with `addContacts`
195
+ - Log activities for meaningful observations
196
+
197
+ But basic contact creation (name + linkedinUrl) happens automatically.
198
+
199
+ ### Smart Contact Deduplication
200
+
201
+ Contacts are auto-deduplicated across all identifier types: profile URL, vanity name (`publicIdentifier`), and LinkedIn URN (`profileUrn`). Duplicates are merged automatically — activities, campaign memberships, and profile data are preserved.
202
+
203
+ The agent can use any identifier type and trust that the CRM resolves to the right contact.
204
+
205
+ ### Campaign Context
206
+
207
+ Each campaign carries a `context` field — the agent's playbook in markdown. `listCampaigns()` returns it for every campaign. Use it to tailor messaging tone, ICP criteria, and follow-up cadence per campaign. Update with `contacts.updateCampaign({ campaignId, context: "..." })`.
156
208
 
157
209
  ## Workflows
158
210
 
159
211
  Each workflow is detailed in its sub-skill. Load the relevant sub-skill when needed.
160
212
 
161
- - **Lead Magnet** — deliver a resource to everyone who engages with a post (comments, likes, invitations). Multi-campaign config at `~/.bereach/lead-magnet.json`. → Lead Magnet sub-skill
162
- - **Lead Gen** — autonomous lead generation. Find and qualify leads daily through multi-angle search, engagement scraping, and a learning loop. BeReach campaigns as the contacts DB. State at `~/.bereach/lead-gen-state.json`. → Lead Gen sub-skill
213
+ - **Lead Magnet** — deliver a resource to everyone who engages with a post (comments, likes, invitations). Config via `agentState.get("lead-magnet-config")`. → Lead Magnet sub-skill
214
+ - **Lead Gen** — autonomous lead generation. Find and qualify leads daily through multi-angle search, engagement scraping, and a learning loop. BeReach campaigns as the contacts DB. State via `agentState.get("lead-gen")`. → Lead Gen sub-skill
163
215
  - **Outreach** — personalized LinkedIn outreach. Connect, message, follow up, adapt. Uses emergent planning (no DAG workflows). State via `agentState.get("outreach")`. → Outreach sub-skill
164
216
 
165
217
  ### Cron
166
218
 
167
219
  Crons are OpenClaw scheduled tasks. Create entries in `~/.openclaw/cron/jobs.json` (via `openclaw cron add`).
168
220
 
169
- **Lead Magnet**3 global crons. Campaign config at `~/.bereach/lead-magnet.json`. Each cron runs one script that loops over all enabled campaigns:
221
+ All crons use `sessionTarget: "isolated"` with `payload.kind: "agentTurn"` each spawns an isolated agent that runs independently and announces results when done. Delivery must include `channel` and `bestEffort: true`. Never use `exec()` directly from a cron; it blocks until the script finishes.
222
+
223
+ **Lead Magnet** — 3 independent hourly crons. Campaign config at `agentState.get("lead-magnet-config")`. Each cron runs one script that loops over all enabled campaigns. They run in parallel since OpenClaw spawns them independently:
170
224
 
171
225
  ```json
172
- { "id": "lm-comments", "every": "1h", "skill": "bereach", "sessionTarget": "spawn", "prompt": "Run lm-comments.ts and report recap" }
173
- { "id": "lm-invitations", "every": "1h", "skill": "bereach", "sessionTarget": "spawn", "prompt": "Run lm-invitations.ts and report recap" }
174
- { "id": "lm-connections", "every": "1h", "skill": "bereach", "sessionTarget": "spawn", "prompt": "Run lm-connections.ts and report recap" }
226
+ {
227
+ "name": "Lead Magnet Comments",
228
+ "enabled": true,
229
+ "schedule": { "kind": "cron", "expr": "0 * * * *", "tz": "Europe/Paris" },
230
+ "sessionTarget": "isolated",
231
+ "wakeMode": "now",
232
+ "payload": {
233
+ "kind": "agentTurn",
234
+ "message": "Run lm-comments.ts for all enabled campaigns. Load config via agentState, validate, process new commenters, report recap.",
235
+ "timeoutSeconds": 600
236
+ },
237
+ "delivery": { "mode": "announce", "channel": "webchat", "bestEffort": true }
238
+ }
175
239
  ```
176
240
 
177
- **Lead Gen** — 1 daily cron. The spawned agent uses tools directly (no pre-generated script):
241
+ ```json
242
+ {
243
+ "name": "Lead Magnet — Invitations",
244
+ "enabled": true,
245
+ "schedule": { "kind": "cron", "expr": "0 * * * *", "tz": "Europe/Paris" },
246
+ "sessionTarget": "isolated",
247
+ "wakeMode": "now",
248
+ "payload": {
249
+ "kind": "agentTurn",
250
+ "message": "Run lm-invitations.ts for all enabled campaigns. Load config via agentState, validate, accept invitations and deliver resource, report recap.",
251
+ "timeoutSeconds": 600
252
+ },
253
+ "delivery": { "mode": "announce", "channel": "webchat", "bestEffort": true }
254
+ }
255
+ ```
178
256
 
179
257
  ```json
180
- { "id": "lead-gen", "every": "1d", "skill": "bereach", "sessionTarget": "spawn", "prompt": "Run daily lead gen using sub/lead-gen.md playbook. Load state via agentState.get('lead-gen'), run priority channels, qualify, store, report recap." }
258
+ {
259
+ "name": "Lead Magnet — Connections",
260
+ "enabled": true,
261
+ "schedule": { "kind": "cron", "expr": "0 * * * *", "tz": "Europe/Paris" },
262
+ "sessionTarget": "isolated",
263
+ "wakeMode": "now",
264
+ "payload": {
265
+ "kind": "agentTurn",
266
+ "message": "Run lm-connections.ts for all enabled campaigns. Load config via agentState, validate, check pending distance 2+ connections, report recap.",
267
+ "timeoutSeconds": 600
268
+ },
269
+ "delivery": { "mode": "announce", "channel": "webchat", "bestEffort": true }
270
+ }
181
271
  ```
182
272
 
183
- **Outreach** — 1 daily cron. Uses emergent planning (no workflows):
273
+ **Lead Gen** — 1 daily cron. The agent uses tools directly (no pre-generated script):
184
274
 
185
275
  ```json
186
- { "id": "outreach", "every": "1d", "skill": "bereach", "sessionTarget": "spawn", "prompt": "Run daily outreach using sub/outreach.md playbook. Load state via agentState.get('outreach'). Process replies first, then accepted connections, then follow-ups, then new connections. Respect daily limits. Update state and recap." }
276
+ {
277
+ "name": "Lead Gen — Daily",
278
+ "enabled": true,
279
+ "schedule": { "kind": "cron", "expr": "0 8 * * *", "tz": "Europe/Paris" },
280
+ "sessionTarget": "isolated",
281
+ "wakeMode": "now",
282
+ "payload": {
283
+ "kind": "agentTurn",
284
+ "message": "Run daily lead gen using sub/lead-gen.md playbook. Discover state via agentState.list({ keysOnly: true }), load 'lead-gen' key if present. Run priority channels, qualify, store, report recap.",
285
+ "timeoutSeconds": 900
286
+ },
287
+ "delivery": { "mode": "announce", "channel": "webchat", "bestEffort": true }
288
+ }
187
289
  ```
188
290
 
189
- Always use `"sessionTarget": "spawn"` for crons that execute scripts or tool-based workflows. This spawns a sub-agent in an isolated session — it runs independently and pushes results back to the user when done, without blocking the main session. Never use `exec()` directly from a cron prompt; it blocks until the script finishes.
291
+ **Outreach** 1 daily cron. Uses emergent planning (no workflows):
292
+
293
+ ```json
294
+ {
295
+ "name": "Outreach — Daily",
296
+ "enabled": true,
297
+ "schedule": { "kind": "cron", "expr": "0 9 * * *", "tz": "Europe/Paris" },
298
+ "sessionTarget": "isolated",
299
+ "wakeMode": "now",
300
+ "payload": {
301
+ "kind": "agentTurn",
302
+ "message": "Run daily outreach using sub/outreach.md playbook. Discover state via agentState.list({ keysOnly: true }), load 'outreach' key. Load campaign contexts via listCampaigns(). Process replies first, then accepted connections, then follow-ups, then new connections. Respect daily limits. Update state and recap.",
303
+ "timeoutSeconds": 900
304
+ },
305
+ "delivery": { "mode": "announce", "channel": "webchat", "bestEffort": true }
306
+ }
307
+ ```
190
308
 
191
309
  **Update check** — detect-only, never auto-upgrade:
192
310
 
193
311
  ```json
194
- { "id": "bereach-update-check", "every": "1d", "skill": "bereach", "sessionTarget": "spawn", "prompt": "Check if a new BeReach plugin version is available. Compare local version from package.json with `npm view bereach-openclaw version`. If newer: notify user once: 'BeReach vX.Y.Z is available (current: vA.B.C). Say upgrade bereach when ready.' Do NOT upgrade automatically." }
312
+ {
313
+ "name": "BeReach — Update Check",
314
+ "enabled": true,
315
+ "schedule": { "kind": "cron", "expr": "0 10 * * *", "tz": "Europe/Paris" },
316
+ "sessionTarget": "isolated",
317
+ "wakeMode": "now",
318
+ "payload": {
319
+ "kind": "agentTurn",
320
+ "message": "Check if a new BeReach plugin version is available. Compare local version from package.json with `npm view bereach-openclaw version`. If newer: notify user once: 'BeReach vX.Y.Z is available (current: vA.B.C). Say upgrade bereach when ready.' Do NOT upgrade automatically.",
321
+ "timeoutSeconds": 120
322
+ },
323
+ "delivery": { "mode": "announce", "channel": "webchat", "bestEffort": true }
324
+ }
195
325
  ```
196
326
 
197
327
  When the user says "upgrade bereach": follow the upgrade workflow in `upgrade-openclaw-bereach.md` — save user state, uninstall, reinstall, recreate scripts from new skill, wait for user confirmation before launching crons.
198
328
 
199
- Remove with `openclaw cron remove <id>`.
329
+ Remove with `openclaw cron remove <name>`.
@@ -4,6 +4,13 @@ description: "Optimize OpenClaw for cost efficiency with Anthropic Claude. Use w
4
4
  lastUpdatedAt: 1773274027
5
5
  ---
6
6
 
7
+ <!--
8
+ AUTO-GENERATED FILE — DO NOT EDIT
9
+ Source of truth: skills/ directory
10
+ Edit the source file, then run: pnpm build:plugins
11
+ Any direct edit to this file WILL be overwritten.
12
+ -->
13
+
7
14
  # OpenClaw Optimization
8
15
 
9
16
  > **Anthropic only.** Skip this skill if the user is not on Anthropic Claude. Proposed during BeReach onboarding or on explicit request. If declined, don't bring it up again.