@forwardimpact/basecamp 2.4.2 → 2.6.0
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/config/scheduler.json +10 -5
- package/package.json +1 -1
- package/src/basecamp.js +101 -729
- package/template/.claude/agents/chief-of-staff.md +14 -3
- package/template/.claude/agents/head-hunter.md +436 -0
- package/template/.claude/agents/librarian.md +1 -1
- package/template/.claude/settings.json +4 -1
- package/template/.claude/skills/analyze-cv/SKILL.md +39 -7
- package/template/.claude/skills/draft-emails/SKILL.md +29 -9
- package/template/.claude/skills/draft-emails/scripts/scan-emails.mjs +4 -4
- package/template/.claude/skills/draft-emails/scripts/send-email.mjs +41 -6
- package/template/.claude/skills/meeting-prep/SKILL.md +7 -4
- package/template/.claude/skills/process-hyprnote/SKILL.md +17 -8
- package/template/.claude/skills/process-hyprnote/scripts/scan.mjs +246 -0
- package/template/.claude/skills/scan-open-candidates/SKILL.md +476 -0
- package/template/.claude/skills/scan-open-candidates/scripts/state.mjs +396 -0
- package/template/.claude/skills/sync-apple-calendar/SKILL.md +41 -0
- package/template/.claude/skills/sync-apple-calendar/scripts/query.mjs +301 -0
- package/template/.claude/skills/synthesize-deck/SKILL.md +296 -0
- package/template/.claude/skills/synthesize-deck/scripts/extract-pptx.mjs +210 -0
- package/template/.claude/skills/track-candidates/SKILL.md +45 -0
- package/template/.claude/skills/workday-requisition/SKILL.md +86 -53
- package/template/.claude/skills/workday-requisition/scripts/parse-workday.mjs +103 -37
- package/template/CLAUDE.md +13 -3
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: scan-open-candidates
|
|
3
|
+
description: >
|
|
4
|
+
Scan publicly available sources for candidates who indicate they are open for
|
|
5
|
+
hire. Uses WebFetch to read public APIs (HN Algolia, GitHub, dev.to).
|
|
6
|
+
Writes prospect notes to knowledge/Prospects/. Maintains
|
|
7
|
+
cursor/dedup state in ~/.cache/fit/basecamp/head-hunter/. Use when the
|
|
8
|
+
head-hunter agent is woken or when the user asks to scan for open candidates.
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# Scan Open Candidates
|
|
12
|
+
|
|
13
|
+
Fetch and filter publicly available candidate posts from platforms where people
|
|
14
|
+
explicitly indicate they are open for hire. This skill handles the web fetching,
|
|
15
|
+
filtering, and deduplication logic.
|
|
16
|
+
|
|
17
|
+
## Trigger
|
|
18
|
+
|
|
19
|
+
Run this skill:
|
|
20
|
+
|
|
21
|
+
- When the head-hunter agent is woken by the scheduler
|
|
22
|
+
- When the user asks to scan for open candidates or prospects
|
|
23
|
+
|
|
24
|
+
## Prerequisites
|
|
25
|
+
|
|
26
|
+
- `WebFetch` tool available (Claude Code built-in — no curl/wget needed)
|
|
27
|
+
- `fit-pathway` CLI available (`npx fit-pathway`)
|
|
28
|
+
- Memory directory at `~/.cache/fit/basecamp/head-hunter/`
|
|
29
|
+
|
|
30
|
+
## Inputs
|
|
31
|
+
|
|
32
|
+
- `~/.cache/fit/basecamp/head-hunter/cursor.tsv` — source rotation state
|
|
33
|
+
- `~/.cache/fit/basecamp/head-hunter/seen.tsv` — deduplication index
|
|
34
|
+
- Framework data via `npx fit-pathway skill --list` and `npx fit-pathway job`
|
|
35
|
+
|
|
36
|
+
## Outputs
|
|
37
|
+
|
|
38
|
+
- `knowledge/Prospects/{Name}.md` — prospect notes
|
|
39
|
+
- `~/.cache/fit/basecamp/head-hunter/cursor.tsv` — updated cursors
|
|
40
|
+
- `~/.cache/fit/basecamp/head-hunter/seen.tsv` — updated seen index
|
|
41
|
+
- `~/.cache/fit/basecamp/head-hunter/prospects.tsv` — updated prospect index
|
|
42
|
+
- `~/.cache/fit/basecamp/head-hunter/log.md` — appended activity log
|
|
43
|
+
- `~/.cache/fit/basecamp/state/head_hunter_triage.md` — triage report
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Source Definitions
|
|
48
|
+
|
|
49
|
+
### 1. Hacker News "Who Wants to Be Hired?"
|
|
50
|
+
|
|
51
|
+
A monthly thread where candidates self-post their availability. Posted on the
|
|
52
|
+
1st of each month on Hacker News.
|
|
53
|
+
|
|
54
|
+
**Find the thread:**
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
WebFetch URL: https://hn.algolia.com/api/v1/search?query=%22Who+wants+to+be+hired%22&tags=ask_hn&hitsPerPage=5
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Parse the JSON response. The first hit with a title matching "Who wants to be
|
|
61
|
+
hired?" and `created_at` in the current or previous month is the target thread.
|
|
62
|
+
|
|
63
|
+
**Fetch candidate posts:**
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
WebFetch URL: https://hn.algolia.com/api/v1/items/{objectID}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The `children` array contains top-level comments — each is one candidate. Parse
|
|
70
|
+
the `text` field (HTML) for:
|
|
71
|
+
|
|
72
|
+
- **Location** — often first line: "Location: New York" or "NYC / Remote"
|
|
73
|
+
- **Remote** — "Remote: Yes" or "Open to remote"
|
|
74
|
+
- **Skills** — tech stack listings, language/framework mentions
|
|
75
|
+
- **Experience** — years, role titles, past companies
|
|
76
|
+
- **Contact** — email (often obfuscated: "name [at] domain [dot] com")
|
|
77
|
+
- **Resume/CV** — links to personal sites, GitHub, LinkedIn
|
|
78
|
+
|
|
79
|
+
**Cursor:** Store the `objectID` of the thread and the ID of the last processed
|
|
80
|
+
child comment.
|
|
81
|
+
|
|
82
|
+
**Rate limit:** HN Algolia API has no strict rate limit but be respectful — one
|
|
83
|
+
fetch per source per wake cycle.
|
|
84
|
+
|
|
85
|
+
### 2. GitHub Open to Work
|
|
86
|
+
|
|
87
|
+
Search for GitHub users whose bio signals availability. The GitHub user search
|
|
88
|
+
API returns candidates with bios, locations, and repository metadata.
|
|
89
|
+
|
|
90
|
+
**Search by location (rotate one query per wake):**
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
WebFetch URL: https://api.github.com/search/users?q=%22open+to+work%22+location:UK&per_page=30&sort=joined&order=desc
|
|
94
|
+
WebFetch URL: https://api.github.com/search/users?q=%22open+to+work%22+location:Europe&per_page=30&sort=joined&order=desc
|
|
95
|
+
WebFetch URL: https://api.github.com/search/users?q=%22looking+for+work%22+location:remote&per_page=30&sort=joined&order=desc
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Alternative bio phrases to search (rotate across wakes):
|
|
99
|
+
|
|
100
|
+
- `"available for hire"`
|
|
101
|
+
- `"seeking opportunities"`
|
|
102
|
+
- `"seeking new role"`
|
|
103
|
+
- `"open to new opportunities"`
|
|
104
|
+
- `"currently exploring"`
|
|
105
|
+
- `"freelance" "available"`
|
|
106
|
+
- `"between roles"`
|
|
107
|
+
- `"on the market"`
|
|
108
|
+
- `"open to opportunities"`
|
|
109
|
+
|
|
110
|
+
Response has `total_count` and `items` array. Each item has `login`, `html_url`,
|
|
111
|
+
`score`.
|
|
112
|
+
|
|
113
|
+
**Fetch full profile for promising candidates:**
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
WebFetch URL: https://api.github.com/users/{login}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Profile fields:
|
|
120
|
+
|
|
121
|
+
- `name` — display name
|
|
122
|
+
- `bio` — bio text (contains open-to-work signals)
|
|
123
|
+
- `location` — geographic location
|
|
124
|
+
- `hireable` — boolean, explicit hire signal
|
|
125
|
+
- `blog` — personal site URL
|
|
126
|
+
- `company` — current employer (null = likely available)
|
|
127
|
+
- `public_repos` — repository count (technical depth indicator)
|
|
128
|
+
- `created_at` — account age (experience proxy)
|
|
129
|
+
|
|
130
|
+
**Cursor:** Store the location query last used and page number. Rotate: UK →
|
|
131
|
+
Europe → Remote → repeat.
|
|
132
|
+
|
|
133
|
+
**Rate limit:** 10 requests/minute unauthenticated. Fetch at most 5 full
|
|
134
|
+
profiles per wake cycle (1 search + 5 profile fetches = 6 requests).
|
|
135
|
+
|
|
136
|
+
### 3. dev.to
|
|
137
|
+
|
|
138
|
+
Developer articles where candidates signal availability via tags.
|
|
139
|
+
|
|
140
|
+
**Fetch articles tagged with job-seeking:**
|
|
141
|
+
|
|
142
|
+
```
|
|
143
|
+
WebFetch URL: https://dev.to/api/articles?tag=opentowork&per_page=25
|
|
144
|
+
WebFetch URL: https://dev.to/api/articles?tag=lookingforwork&per_page=25
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
For articles, parse `title`, `description`, `user.name`, `user.username`, `url`,
|
|
148
|
+
`tag_list`, `published_at`.
|
|
149
|
+
|
|
150
|
+
Skip articles older than 90 days — the candidate may no longer be looking.
|
|
151
|
+
|
|
152
|
+
Additional tags to try when primary tags yield no results:
|
|
153
|
+
|
|
154
|
+
- `jobsearch`
|
|
155
|
+
- `career`
|
|
156
|
+
- `hiring`
|
|
157
|
+
- `job`
|
|
158
|
+
- `remotework`
|
|
159
|
+
|
|
160
|
+
**Cursor:** Store the `id` of the most recent article processed.
|
|
161
|
+
|
|
162
|
+
**Rate limit:** dev.to API allows 30 requests per 30 seconds. One fetch per wake
|
|
163
|
+
is fine.
|
|
164
|
+
|
|
165
|
+
---
|
|
166
|
+
|
|
167
|
+
## Creative Fallback Strategies
|
|
168
|
+
|
|
169
|
+
When the primary query for a source yields zero new prospects after filtering,
|
|
170
|
+
try these alternative approaches before reporting an empty scan.
|
|
171
|
+
|
|
172
|
+
### Strategy 1: Alternative Search Terms
|
|
173
|
+
|
|
174
|
+
Each source has multiple query variations. If the first query returns nothing
|
|
175
|
+
new, try the next variation:
|
|
176
|
+
|
|
177
|
+
**HN:**
|
|
178
|
+
|
|
179
|
+
- Check the previous month's "Who Wants to Be Hired?" thread (candidates post
|
|
180
|
+
late or threads stay active)
|
|
181
|
+
- Search for `"Who is hiring"` threads — candidates sometimes post in the wrong
|
|
182
|
+
thread, and comments may link to candidate profiles
|
|
183
|
+
- Try:
|
|
184
|
+
`https://hn.algolia.com/api/v1/search?query=%22freelancer+available%22&tags=comment`
|
|
185
|
+
|
|
186
|
+
**GitHub:**
|
|
187
|
+
|
|
188
|
+
- Search by skill + availability instead of just bio phrases:
|
|
189
|
+
```
|
|
190
|
+
WebFetch URL: https://api.github.com/search/users?q=%22data+engineering%22+%22open+to+work%22&per_page=30&sort=joined&order=desc
|
|
191
|
+
WebFetch URL: https://api.github.com/search/users?q=%22full+stack%22+%22available+for+hire%22&per_page=30&sort=joined&order=desc
|
|
192
|
+
WebFetch URL: https://api.github.com/search/users?q=%22devops%22+%22looking+for%22&per_page=30&sort=joined&order=desc
|
|
193
|
+
```
|
|
194
|
+
- Search repos with README availability signals:
|
|
195
|
+
```
|
|
196
|
+
WebFetch URL: https://api.github.com/search/repositories?q=%22hire+me%22+in:readme&sort=updated&order=desc&per_page=10
|
|
197
|
+
```
|
|
198
|
+
- Try different location terms: `Greece`, `Athens`, `Warsaw`, `Bucharest`,
|
|
199
|
+
`Sofia`, `Manchester`, `Edinburgh`
|
|
200
|
+
|
|
201
|
+
**dev.to:**
|
|
202
|
+
|
|
203
|
+
- Try broader tags: `jobsearch`, `career`, `remotework`
|
|
204
|
+
- Search articles directly:
|
|
205
|
+
```
|
|
206
|
+
WebFetch URL: https://dev.to/api/articles?tag=career&per_page=25
|
|
207
|
+
```
|
|
208
|
+
Then filter article titles/descriptions for availability signals.
|
|
209
|
+
|
|
210
|
+
### Strategy 2: Relax Filters
|
|
211
|
+
|
|
212
|
+
If geographic filtering eliminated all candidates:
|
|
213
|
+
|
|
214
|
+
- Re-scan the same results without the location filter
|
|
215
|
+
- Candidates without stated locations may still be open to target regions
|
|
216
|
+
- Mark these as "location unconfirmed" in the prospect note
|
|
217
|
+
|
|
218
|
+
If skill alignment filtered everyone out:
|
|
219
|
+
|
|
220
|
+
- Lower the minimum bar from 2 framework skills to 1
|
|
221
|
+
- Look for transferable skills (e.g., strong Python → likely data integration
|
|
222
|
+
capability)
|
|
223
|
+
- Consider adjacent skill indicators (e.g., "machine learning" implies data
|
|
224
|
+
skills)
|
|
225
|
+
|
|
226
|
+
### Strategy 3: Cross-Reference
|
|
227
|
+
|
|
228
|
+
When a source yields very few results, cross-reference what you do find:
|
|
229
|
+
|
|
230
|
+
- If a GitHub profile links to a blog or portfolio, check it for more detail
|
|
231
|
+
(via WebFetch) before deciding on skill fit
|
|
232
|
+
- If an HN post mentions a GitHub username, fetch their GitHub profile for
|
|
233
|
+
richer signal
|
|
234
|
+
|
|
235
|
+
### Logging Alternatives
|
|
236
|
+
|
|
237
|
+
Log every alternative approach in `log.md`:
|
|
238
|
+
|
|
239
|
+
```markdown
|
|
240
|
+
## 2026-03-05 14:00
|
|
241
|
+
|
|
242
|
+
Source: github_open_to_work
|
|
243
|
+
Primary query: "open to work" location:UK — 30 results, 0 new after dedup
|
|
244
|
+
Alternative 1: "data engineering" "open to work" — 12 results, 1 new prospect
|
|
245
|
+
Alternative 2: "full stack" "available for hire" — 8 results, 0 new
|
|
246
|
+
Stopped after 2 alternatives (1 prospect found)
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## Failure Handling
|
|
252
|
+
|
|
253
|
+
When a WebFetch fails (HTTP 4xx, 5xx, timeout, empty response, or redirect to a
|
|
254
|
+
block page), handle it gracefully:
|
|
255
|
+
|
|
256
|
+
1. **Record the failure** in `failures.tsv`:
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
sed -i '' "s/^{source}\t.*/&/" ~/.cache/fit/basecamp/head-hunter/failures.tsv
|
|
260
|
+
# Or increment the count and update last_error
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
2. **Do not retry** the same source in this wake cycle. Move on.
|
|
264
|
+
|
|
265
|
+
3. **Suspend after 3 consecutive failures.** During source selection, skip any
|
|
266
|
+
source with count ≥ 3 in `failures.tsv`. The agent should still attempt
|
|
267
|
+
suspended sources once every 7 days to detect recovery.
|
|
268
|
+
|
|
269
|
+
4. **Common failure patterns:**
|
|
270
|
+
- **503 with HTML redirect** — Corporate proxy blocking the domain
|
|
271
|
+
(social-networking category). Source will not recover without network
|
|
272
|
+
change.
|
|
273
|
+
- **403 Forbidden** — API requires authentication or blocks automated
|
|
274
|
+
requests. Source may not recover.
|
|
275
|
+
- **429 Too Many Requests** — Rate limited. Will recover. Don't suspend
|
|
276
|
+
permanently.
|
|
277
|
+
- **Empty response / timeout** — Transient. Will likely recover.
|
|
278
|
+
|
|
279
|
+
5. **Log all failures** in `log.md` with the HTTP status and error details.
|
|
280
|
+
|
|
281
|
+
6. **Reset on success.** When a previously-failing source succeeds, reset its
|
|
282
|
+
count to 0 in `failures.tsv`.
|
|
283
|
+
|
|
284
|
+
## Filtering Pipeline
|
|
285
|
+
|
|
286
|
+
Apply these filters to each candidate post, in order:
|
|
287
|
+
|
|
288
|
+
### Filter 1: Open-for-Hire Signal
|
|
289
|
+
|
|
290
|
+
- HN "Who Wants to Be Hired?" — **auto-pass** (thread is explicitly opt-in)
|
|
291
|
+
- GitHub — must have `hireable: true`, or bio containing open-to-work phrases
|
|
292
|
+
- dev.to — must be tagged `opentowork` or `lookingforwork`
|
|
293
|
+
|
|
294
|
+
### Filter 2: Deduplication
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
grep -q "^{source}\t{post_id}\t" ~/.cache/fit/basecamp/head-hunter/seen.tsv
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
If found, skip. Otherwise continue.
|
|
301
|
+
|
|
302
|
+
### Filter 3: Geographic Fit
|
|
303
|
+
|
|
304
|
+
Look for location mentions. Prefer candidates in or open to:
|
|
305
|
+
|
|
306
|
+
- **US East Coast** (NYC, Boston, DC, Philadelphia, etc.)
|
|
307
|
+
- **UK** (London, Manchester, Edinburgh, etc.)
|
|
308
|
+
- **EU** — especially Greece, Poland, Romania, Bulgaria
|
|
309
|
+
- **Remote / Anywhere / Global**
|
|
310
|
+
|
|
311
|
+
Skip candidates explicitly locked to incompatible locations (e.g., "San
|
|
312
|
+
Francisco only", "APAC only"). When location is ambiguous or unstated, include
|
|
313
|
+
the candidate — let the user decide.
|
|
314
|
+
|
|
315
|
+
### Filter 4: Skill Alignment
|
|
316
|
+
|
|
317
|
+
Run `npx fit-pathway skill --list` to get the framework skill inventory. Check
|
|
318
|
+
whether the candidate mentions skills that map to framework capabilities:
|
|
319
|
+
|
|
320
|
+
**Strong signals (forward-deployed track):**
|
|
321
|
+
|
|
322
|
+
- Multiple industries or domains in background
|
|
323
|
+
- Customer-facing project experience
|
|
324
|
+
- Data integration, analytics, visualization
|
|
325
|
+
- Full-stack development with business context
|
|
326
|
+
- Non-traditional path (law, policy, academia → tech)
|
|
327
|
+
- AI/ML tool proficiency (Claude, GPT, Cursor, "vibe coding")
|
|
328
|
+
|
|
329
|
+
**Strong signals (platform track):**
|
|
330
|
+
|
|
331
|
+
- Infrastructure, cloud platforms, DevOps
|
|
332
|
+
- Architecture and system design
|
|
333
|
+
- API design, shared services
|
|
334
|
+
- Performance, scalability, reliability
|
|
335
|
+
|
|
336
|
+
**Minimum bar:** At least 2 framework-relevant skills must be identifiable from
|
|
337
|
+
the post. Skip candidates with purely non-technical profiles.
|
|
338
|
+
|
|
339
|
+
### Filter 5: Experience Level
|
|
340
|
+
|
|
341
|
+
Estimate career level from signals:
|
|
342
|
+
|
|
343
|
+
| Signal | Likely Level |
|
|
344
|
+
| ------------------------------------------- | ------------ |
|
|
345
|
+
| "junior", "entry-level", 0-2 years | J040 |
|
|
346
|
+
| "mid-level", 3-5 years | J060 |
|
|
347
|
+
| "senior", 5-8 years, "lead" | J070 |
|
|
348
|
+
| "staff", "principal", 8+ years, "architect" | J090+ |
|
|
349
|
+
|
|
350
|
+
When uncertain, default to J060 with low confidence.
|
|
351
|
+
|
|
352
|
+
## Prospect Note Format
|
|
353
|
+
|
|
354
|
+
Write to `knowledge/Prospects/{Name}.md`:
|
|
355
|
+
|
|
356
|
+
```markdown
|
|
357
|
+
# {Name}
|
|
358
|
+
|
|
359
|
+
## Info
|
|
360
|
+
**Source:** [{platform}]({permalink})
|
|
361
|
+
**Date found:** {YYYY-MM-DD}
|
|
362
|
+
**Location:** {location or "Not specified"}
|
|
363
|
+
**Estimated level:** {J040–J110} (confidence: {high/medium/low})
|
|
364
|
+
**Best track fit:** {forward_deployed / platform / either}
|
|
365
|
+
**Match strength:** {strong / moderate}
|
|
366
|
+
|
|
367
|
+
## Profile
|
|
368
|
+
{2-4 sentences: who they are, what they do, why they match. Reference specific
|
|
369
|
+
framework skill IDs in parentheses where possible.}
|
|
370
|
+
|
|
371
|
+
## Framework Alignment
|
|
372
|
+
**Matching skills:** {comma-separated skill IDs}
|
|
373
|
+
**Key strengths:** {what stands out relative to the framework}
|
|
374
|
+
**Gaps:** {notable missing skills for the estimated role}
|
|
375
|
+
|
|
376
|
+
## Source Post
|
|
377
|
+
> {Brief excerpt or summary of the original post — 2-3 lines max}
|
|
378
|
+
|
|
379
|
+
## Notes
|
|
380
|
+
{Additional observations: polymath signals, AI tool usage, unusual background
|
|
381
|
+
combinations, anything noteworthy for the user}
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
**Naming:** Use the candidate's display name as given. If only a username is
|
|
385
|
+
available, use the username. Never fabricate real names.
|
|
386
|
+
|
|
387
|
+
## State Management Script
|
|
388
|
+
|
|
389
|
+
**Use the state script for ALL state file operations.** Do NOT write bespoke
|
|
390
|
+
scripts to update cursor, seen, prospects, failures, or log files.
|
|
391
|
+
|
|
392
|
+
node .claude/skills/scan-open-candidates/scripts/state.mjs <command> [args]
|
|
393
|
+
|
|
394
|
+
### Commands
|
|
395
|
+
|
|
396
|
+
**Cursor** (source rotation):
|
|
397
|
+
|
|
398
|
+
```bash
|
|
399
|
+
# Check which source to scan next
|
|
400
|
+
node scripts/state.mjs cursor list
|
|
401
|
+
|
|
402
|
+
# Get cursor for a specific source
|
|
403
|
+
node scripts/state.mjs cursor get github_open_to_work
|
|
404
|
+
|
|
405
|
+
# Update cursor after scanning
|
|
406
|
+
node scripts/state.mjs cursor set github_open_to_work "2026-03-09T22:00:00Z" "UK-done_next:Europe"
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
**Seen** (deduplication):
|
|
410
|
+
|
|
411
|
+
```bash
|
|
412
|
+
# Check if a candidate was already seen (exit 0=seen, 1=new)
|
|
413
|
+
node scripts/state.mjs seen check github_open_to_work mxmxmx333
|
|
414
|
+
|
|
415
|
+
# Mark one ID as seen
|
|
416
|
+
node scripts/state.mjs seen add github_open_to_work mxmxmx333
|
|
417
|
+
|
|
418
|
+
# Mark multiple IDs as seen in one call
|
|
419
|
+
node scripts/state.mjs seen batch github_open_to_work id1 id2 id3 id4
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
**Prospects**:
|
|
423
|
+
|
|
424
|
+
```bash
|
|
425
|
+
# Add a new prospect
|
|
426
|
+
node scripts/state.mjs prospect add "Hasan Cam" github_open_to_work strong "J060-J070 platform"
|
|
427
|
+
|
|
428
|
+
# List recent prospects
|
|
429
|
+
node scripts/state.mjs prospect list --limit 10
|
|
430
|
+
|
|
431
|
+
# Count total prospects
|
|
432
|
+
node scripts/state.mjs prospect count
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
**Failures**:
|
|
436
|
+
|
|
437
|
+
```bash
|
|
438
|
+
# Check failure count (for source selection — skip if ≥3)
|
|
439
|
+
node scripts/state.mjs failure get mastodon_hachyderm
|
|
440
|
+
|
|
441
|
+
# Record a fetch failure
|
|
442
|
+
node scripts/state.mjs failure increment mastodon_hachyderm
|
|
443
|
+
|
|
444
|
+
# Reset after successful fetch
|
|
445
|
+
node scripts/state.mjs failure reset github_open_to_work
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
**Logging**:
|
|
449
|
+
|
|
450
|
+
```bash
|
|
451
|
+
# Append a formatted wake cycle entry
|
|
452
|
+
node scripts/state.mjs log-wake github_open_to_work "Primary query: 'open to work' location:UK — 30 results, 2 new prospects"
|
|
453
|
+
|
|
454
|
+
# Append raw text
|
|
455
|
+
node scripts/state.mjs log "Manual note about source rotation"
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
**Summary** (state overview):
|
|
459
|
+
|
|
460
|
+
```bash
|
|
461
|
+
node scripts/state.mjs summary
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
## Quality Checklist
|
|
465
|
+
|
|
466
|
+
- [ ] Selected the least-recently-checked source from cursor.tsv
|
|
467
|
+
- [ ] Fetched data using WebFetch (not curl/wget)
|
|
468
|
+
- [ ] Applied all 5 filters in order
|
|
469
|
+
- [ ] Checked seen.tsv before processing each post
|
|
470
|
+
- [ ] Used fit-pathway to benchmark each prospect against a real job
|
|
471
|
+
- [ ] Prospect notes follow the standard format
|
|
472
|
+
- [ ] Updated cursor.tsv with new position
|
|
473
|
+
- [ ] Appended all processed post IDs to seen.tsv
|
|
474
|
+
- [ ] Appended new prospects to prospects.tsv
|
|
475
|
+
- [ ] Appended wake summary to log.md
|
|
476
|
+
- [ ] Wrote triage report to state directory
|