@forwardimpact/basecamp 2.3.0 → 2.3.1
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/package.json
CHANGED
|
@@ -26,6 +26,8 @@ their email.
|
|
|
26
26
|
|
|
27
27
|
- `~/.cache/fit/basecamp/state/apple_mail_last_sync` — last sync timestamp
|
|
28
28
|
(single-line text file)
|
|
29
|
+
- `~/.cache/fit/basecamp/state/apple_mail_last_rowid` — highest message ROWID
|
|
30
|
+
seen at last sync (single-line text file)
|
|
29
31
|
- `~/Library/Mail/V*/MailData/Envelope Index` — Apple Mail SQLite database
|
|
30
32
|
|
|
31
33
|
## Outputs
|
|
@@ -36,6 +38,8 @@ their email.
|
|
|
36
38
|
attachment files for each thread (PDFs, images, documents, etc.)
|
|
37
39
|
- `~/.cache/fit/basecamp/state/apple_mail_last_sync` — updated with new sync
|
|
38
40
|
timestamp
|
|
41
|
+
- `~/.cache/fit/basecamp/state/apple_mail_last_rowid` — updated with highest
|
|
42
|
+
ROWID seen
|
|
39
43
|
|
|
40
44
|
---
|
|
41
45
|
|
|
@@ -53,13 +57,17 @@ The script:
|
|
|
53
57
|
1. Finds the Mail database (`~/Library/Mail/V*/MailData/Envelope Index`)
|
|
54
58
|
2. Loads last sync timestamp (or defaults to `--days` days ago for first sync)
|
|
55
59
|
3. Discovers the thread grouping column (`conversation_id` or `thread_id`)
|
|
56
|
-
4.
|
|
57
|
-
5.
|
|
60
|
+
4. Loads last-seen ROWID (or defaults to 0 for first sync)
|
|
61
|
+
5. Finds threads with new messages since last sync (up to 500), using both
|
|
62
|
+
timestamp and ROWID to catch late-arriving emails (emails downloaded after
|
|
63
|
+
a delay may have `date_received` before the last sync timestamp, but their
|
|
64
|
+
ROWID will be higher than the last-seen ROWID)
|
|
65
|
+
6. For each thread: fetches messages, batch-fetches recipients and attachment
|
|
58
66
|
metadata, parses `.emlx` files for full email bodies (falling back to
|
|
59
67
|
database summaries), copies attachment files to the output directory
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
68
|
+
7. Writes one markdown file per thread to `~/.cache/fit/basecamp/apple_mail/`
|
|
69
|
+
8. Updates sync state (timestamp and max ROWID)
|
|
70
|
+
9. Reports summary (threads processed, files written)
|
|
63
71
|
|
|
64
72
|
The script imports `scripts/parse-emlx.mjs` to extract plain text bodies from
|
|
65
73
|
`.emlx` / `.partial.emlx` files (handles HTML-only emails by stripping tags).
|
|
@@ -130,18 +130,27 @@ For each candidate found in a recruitment email, extract:
|
|
|
130
130
|
|
|
131
131
|
| Field | Source | Required |
|
|
132
132
|
| ----------------- | ------------------------------------------------- | ------------------- |
|
|
133
|
-
| **Name**
|
|
134
|
-
| **
|
|
135
|
-
| **Rate**
|
|
136
|
-
| **Availability**
|
|
137
|
-
| **English**
|
|
138
|
-
| **Location**
|
|
139
|
-
| **Source agency**
|
|
140
|
-
| **Recruiter**
|
|
141
|
-
| **CV path**
|
|
142
|
-
| **Skills**
|
|
143
|
-
| **Gender**
|
|
144
|
-
| **Summary**
|
|
133
|
+
| **Name** | Filename, email body, CV | Yes |
|
|
134
|
+
| **Title** | Email body, CV — the candidate's professional title/function | Yes |
|
|
135
|
+
| **Rate** | Email body (e.g. "$120/hr", "€80/h") | If available |
|
|
136
|
+
| **Availability** | Email body (e.g. "1 month notice", "immediately") | If available |
|
|
137
|
+
| **English** | Email body (e.g. "B2", "Upper-intermediate") | If available |
|
|
138
|
+
| **Location** | Email body, CV | If available |
|
|
139
|
+
| **Source agency** | Sender domain → Organization | Yes |
|
|
140
|
+
| **Recruiter** | Email sender or CC'd recruiter | Yes |
|
|
141
|
+
| **CV path** | Attachment directory | If available |
|
|
142
|
+
| **Skills** | Email body, CV | If available |
|
|
143
|
+
| **Gender** | Name, pronouns, recruiter context | If identifiable |
|
|
144
|
+
| **Summary** | Email body, CV | Yes — 2-3 sentences |
|
|
145
|
+
| **Role** | Internal requisition profile being hired against | If available |
|
|
146
|
+
| **Req** | Requisition ID from hiring system | If available |
|
|
147
|
+
| **Internal/External**| Whether candidate is internal or external | If available |
|
|
148
|
+
| **Model** | Engagement model (B2B, Direct Hire, etc.) | If available |
|
|
149
|
+
| **Current title** | CV or email body | If available |
|
|
150
|
+
| **Email** | Email body, CV, signature | If available |
|
|
151
|
+
| **Phone** | Email body, CV, signature | If available |
|
|
152
|
+
| **LinkedIn** | Email body, CV | If available |
|
|
153
|
+
| **Also known as** | Alternate name spellings or transliterations | If available |
|
|
145
154
|
|
|
146
155
|
### Determining Gender
|
|
147
156
|
|
|
@@ -193,9 +202,11 @@ Assign a status based on the email context:
|
|
|
193
202
|
| `screening` | Under review, questions asked about the candidate |
|
|
194
203
|
| `first-interview` | First interview scheduled or completed |
|
|
195
204
|
| `second-interview` | Second interview scheduled or completed |
|
|
205
|
+
| `work-trial` | Paid work trial or assessment project in progress |
|
|
196
206
|
| `offer` | Offer extended |
|
|
197
207
|
| `hired` | Accepted and onboarding |
|
|
198
208
|
| `rejected` | Explicitly passed on ("not a fit", "pass", "decline") |
|
|
209
|
+
| `withdrawn` | Candidate withdrew from the process |
|
|
199
210
|
| `on-hold` | Paused, waiting on notice period, or deferred |
|
|
200
211
|
|
|
201
212
|
**Default to `new`** if no response signals are found. Read the full thread
|
|
@@ -207,7 +218,10 @@ Look for these patterns in the hiring manager's replies:
|
|
|
207
218
|
|
|
208
219
|
- "let's schedule" / "set up an interview" → `first-interview`
|
|
209
220
|
- "second round" / "follow-up interview" → `second-interview`
|
|
221
|
+
- "work trial" / "assessment project" / "paid trial" → `work-trial`
|
|
210
222
|
- "not what we're looking for" / "pass" → `rejected`
|
|
223
|
+
- "candidate withdrew" / "no longer interested" / "accepted another offer" →
|
|
224
|
+
`withdrawn`
|
|
211
225
|
- "extend an offer" / "make an offer" → `offer`
|
|
212
226
|
- "they've accepted" / "start date" → `hired`
|
|
213
227
|
- "put on hold" / "come back to later" → `on-hold`
|
|
@@ -244,7 +258,7 @@ Then create `knowledge/Candidates/{Full Name}/brief.md`:
|
|
|
244
258
|
# {Full Name}
|
|
245
259
|
|
|
246
260
|
## Info
|
|
247
|
-
**
|
|
261
|
+
**Title:** {professional title/function}
|
|
248
262
|
**Rate:** {rate or "—"}
|
|
249
263
|
**Availability:** {availability or "—"}
|
|
250
264
|
**English:** {level or "—"}
|
|
@@ -254,6 +268,7 @@ Then create `knowledge/Candidates/{Full Name}/brief.md`:
|
|
|
254
268
|
**Status:** {pipeline status}
|
|
255
269
|
**First seen:** {date profile was shared, YYYY-MM-DD}
|
|
256
270
|
**Last activity:** {date of most recent thread activity, YYYY-MM-DD}
|
|
271
|
+
{extra fields here — see below}
|
|
257
272
|
|
|
258
273
|
## Summary
|
|
259
274
|
{2-3 sentences: role, experience level, key strengths}
|
|
@@ -271,7 +286,11 @@ Then create `knowledge/Candidates/{Full Name}/brief.md`:
|
|
|
271
286
|
## Skills
|
|
272
287
|
{comma-separated skill tags}
|
|
273
288
|
|
|
289
|
+
## Interview Notes
|
|
290
|
+
{interview feedback, structured by date — omit section if no interviews yet}
|
|
291
|
+
|
|
274
292
|
## Notes
|
|
293
|
+
{free-form observations — always present, even if empty}
|
|
275
294
|
```
|
|
276
295
|
|
|
277
296
|
If a CV attachment exists, **copy it into the candidate directory** before
|
|
@@ -279,6 +298,37 @@ writing the note.
|
|
|
279
298
|
|
|
280
299
|
If no CV attachment exists, omit the `## CV` section entirely.
|
|
281
300
|
|
|
301
|
+
### Extra Info Fields
|
|
302
|
+
|
|
303
|
+
Place any of these **after Last activity** in the order shown, only when
|
|
304
|
+
available:
|
|
305
|
+
|
|
306
|
+
```markdown
|
|
307
|
+
**Role:** {internal requisition profile, e.g. "Staff Engineer"}
|
|
308
|
+
**Req:** {requisition ID, e.g. "4950237 — Principal Software Engineer"}
|
|
309
|
+
**Internal/External:** {Internal / External / External (Prior Worker)}
|
|
310
|
+
**Model:** {engagement model, e.g. "B2B (via Agency) — conversion to FTE not possible"}
|
|
311
|
+
**Current title:** {current job title and employer}
|
|
312
|
+
**Email:** {personal or work email}
|
|
313
|
+
**Phone:** {phone number}
|
|
314
|
+
**LinkedIn:** {LinkedIn profile URL}
|
|
315
|
+
**Also known as:** {alternate name spellings}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### Additional Sections
|
|
319
|
+
|
|
320
|
+
Some candidates accumulate richer profiles over time. These optional sections go
|
|
321
|
+
**after Skills and before Notes**, in this order:
|
|
322
|
+
|
|
323
|
+
1. `## Education` — degrees, institutions, years
|
|
324
|
+
2. `## Certifications` — professional certifications
|
|
325
|
+
3. `## Work History` — chronological career history (when extracted from CV)
|
|
326
|
+
4. `## Key Facts` — notable bullet points from CV review
|
|
327
|
+
5. `## Interview Notes` — structured by date as `### YYYY-MM-DD — {description}`
|
|
328
|
+
|
|
329
|
+
`## Notes` is always the **last section**. If an `## Open Items` section exists
|
|
330
|
+
(pending questions or follow-ups), place it after Notes.
|
|
331
|
+
|
|
282
332
|
### For EXISTING candidates
|
|
283
333
|
|
|
284
334
|
Read `knowledge/Candidates/{Full Name}/brief.md`, then apply targeted edits:
|
|
@@ -364,6 +414,11 @@ produces a full framework-aligned assessment.
|
|
|
364
414
|
- [ ] Scanned all new/changed email threads for recruitment signals
|
|
365
415
|
- [ ] Extracted all candidates found (check attachment directories too)
|
|
366
416
|
- [ ] Each candidate has a complete note with all available fields
|
|
417
|
+
- [ ] Info fields are in standard order (Title, Rate, Availability, English,
|
|
418
|
+
Location, Gender, Source, Status, First seen, Last activity, then extras)
|
|
419
|
+
- [ ] Sections are in standard order (Info → Summary → CV → Connected to →
|
|
420
|
+
Pipeline → Skills → Education/Certifications/Work History/Key Facts →
|
|
421
|
+
Interview Notes → Notes → Open Items)
|
|
367
422
|
- [ ] CV paths are correct and point to actual files
|
|
368
423
|
- [ ] Pipeline status reflects the latest thread activity
|
|
369
424
|
- [ ] Timeline entries are in chronological order
|
|
@@ -29,7 +29,8 @@ Run this skill when:
|
|
|
29
29
|
|
|
30
30
|
## Outputs
|
|
31
31
|
|
|
32
|
-
- `.claude/skills
|
|
32
|
+
- `.claude/skills/<skill-name>/CHANGELOG.md` — per-skill changelog of local
|
|
33
|
+
changes, one per modified skill directory
|
|
33
34
|
|
|
34
35
|
---
|
|
35
36
|
|
|
@@ -41,21 +42,22 @@ Use git to find all skill files that have been added, modified, or deleted since
|
|
|
41
42
|
the last changelog entry (or since initial commit if no changelog exists).
|
|
42
43
|
|
|
43
44
|
```bash
|
|
44
|
-
# Find the date of the last changelog entry (if any)
|
|
45
|
-
head -20 .claude/skills
|
|
45
|
+
# Find the date of the last changelog entry for a skill (if any)
|
|
46
|
+
head -20 .claude/skills/<skill-name>/CHANGELOG.md 2>/dev/null
|
|
46
47
|
|
|
47
48
|
# List changed skill files since last documented change
|
|
48
49
|
git log --oneline --name-status -- '.claude/skills/'
|
|
49
50
|
```
|
|
50
51
|
|
|
51
|
-
If `.claude/skills
|
|
52
|
-
and only look at changes after that date:
|
|
52
|
+
If a skill already has a `.claude/skills/<skill-name>/CHANGELOG.md`, read the
|
|
53
|
+
most recent entry date and only look at changes after that date:
|
|
53
54
|
|
|
54
55
|
```bash
|
|
55
|
-
git log --after="<last-entry-date>" --name-status -- '.claude/skills
|
|
56
|
+
git log --after="<last-entry-date>" --name-status -- '.claude/skills/<skill-name>/'
|
|
56
57
|
```
|
|
57
58
|
|
|
58
|
-
If no changelog exists, consider all commits that touched
|
|
59
|
+
If no changelog exists for a skill, consider all commits that touched that
|
|
60
|
+
skill's directory.
|
|
59
61
|
|
|
60
62
|
### Step 2: Classify Each Change
|
|
61
63
|
|
|
@@ -106,18 +108,17 @@ Bad descriptions:
|
|
|
106
108
|
|
|
107
109
|
### Step 4: Write the Changelog
|
|
108
110
|
|
|
109
|
-
|
|
111
|
+
For each changed skill, create or update its
|
|
112
|
+
`.claude/skills/<skill-name>/CHANGELOG.md` with the following format:
|
|
110
113
|
|
|
111
114
|
```markdown
|
|
112
|
-
#
|
|
115
|
+
# <skill-name> Changelog
|
|
113
116
|
|
|
114
|
-
Changes to
|
|
115
|
-
|
|
117
|
+
Changes to this skill that should be considered for upstream inclusion in the
|
|
118
|
+
Forward Impact monorepo.
|
|
116
119
|
|
|
117
120
|
## <YYYY-MM-DD>
|
|
118
121
|
|
|
119
|
-
### <skill-name> (added|modified|removed)
|
|
120
|
-
|
|
121
122
|
**What:** <one-line summary of the change>
|
|
122
123
|
|
|
123
124
|
**Why:** <the problem or improvement that motivated it>
|
|
@@ -128,14 +129,20 @@ inclusion in the Forward Impact monorepo.
|
|
|
128
129
|
---
|
|
129
130
|
```
|
|
130
131
|
|
|
131
|
-
Entries are in **reverse chronological order** (newest first).
|
|
132
|
-
|
|
132
|
+
Entries are in **reverse chronological order** (newest first). Each skill has
|
|
133
|
+
its own changelog file inside its directory.
|
|
134
|
+
|
|
135
|
+
For **new skills**, create the `CHANGELOG.md` alongside the `SKILL.md` with a
|
|
136
|
+
single `added` entry describing the skill's purpose.
|
|
137
|
+
|
|
138
|
+
For **removed skills**, the changelog should be the last file remaining in the
|
|
139
|
+
skill directory, documenting why the skill was removed.
|
|
133
140
|
|
|
134
|
-
### Step 5: Review the
|
|
141
|
+
### Step 5: Review the Changelogs
|
|
135
142
|
|
|
136
|
-
After writing, read
|
|
143
|
+
After writing, read each changelog back and verify:
|
|
137
144
|
|
|
138
|
-
- [ ] Every changed skill has
|
|
145
|
+
- [ ] Every changed skill has a `CHANGELOG.md` in its directory
|
|
139
146
|
- [ ] Each entry has What, Why, and Details sections
|
|
140
147
|
- [ ] Descriptions are specific enough for an upstream maintainer to act on
|
|
141
148
|
- [ ] New skills include a brief description of their purpose
|
|
@@ -145,16 +152,16 @@ After writing, read the changelog back and verify:
|
|
|
145
152
|
|
|
146
153
|
## Example Output
|
|
147
154
|
|
|
155
|
+
`.claude/skills/track-candidates/CHANGELOG.md`:
|
|
156
|
+
|
|
148
157
|
```markdown
|
|
149
|
-
#
|
|
158
|
+
# track-candidates Changelog
|
|
150
159
|
|
|
151
|
-
Changes to
|
|
152
|
-
|
|
160
|
+
Changes to this skill that should be considered for upstream inclusion in the
|
|
161
|
+
Forward Impact monorepo.
|
|
153
162
|
|
|
154
163
|
## 2026-03-01
|
|
155
164
|
|
|
156
|
-
### track-candidates (modified)
|
|
157
|
-
|
|
158
165
|
**What:** Added gender field extraction for diversity tracking
|
|
159
166
|
|
|
160
167
|
**Why:** Recruitment pipeline lacked diversity metrics — pool composition was
|
|
@@ -166,7 +173,18 @@ invisible without structured gender data.
|
|
|
166
173
|
- Added explicit note that field has no bearing on hiring decisions
|
|
167
174
|
- Updated quality checklist to include gender field verification
|
|
168
175
|
|
|
169
|
-
|
|
176
|
+
---
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
`.claude/skills/process-hyprnote/CHANGELOG.md`:
|
|
180
|
+
|
|
181
|
+
```markdown
|
|
182
|
+
# process-hyprnote Changelog
|
|
183
|
+
|
|
184
|
+
Changes to this skill that should be considered for upstream inclusion in the
|
|
185
|
+
Forward Impact monorepo.
|
|
186
|
+
|
|
187
|
+
## 2026-03-01
|
|
170
188
|
|
|
171
189
|
**What:** New skill for processing Hyprnote meeting recordings
|
|
172
190
|
|
|
@@ -180,10 +198,17 @@ they weren't being integrated into the knowledge base.
|
|
|
180
198
|
- Links attendees to `knowledge/People/` entries
|
|
181
199
|
|
|
182
200
|
---
|
|
201
|
+
```
|
|
183
202
|
|
|
184
|
-
|
|
203
|
+
`.claude/skills/extract-entities/CHANGELOG.md`:
|
|
185
204
|
|
|
186
|
-
|
|
205
|
+
```markdown
|
|
206
|
+
# extract-entities Changelog
|
|
207
|
+
|
|
208
|
+
Changes to this skill that should be considered for upstream inclusion in the
|
|
209
|
+
Forward Impact monorepo.
|
|
210
|
+
|
|
211
|
+
## 2026-02-15
|
|
187
212
|
|
|
188
213
|
**What:** Increased batch size from 5 to 10 files per run
|
|
189
214
|
|
|
@@ -200,7 +225,8 @@ dozens of runs to catch up after a week of email.
|
|
|
200
225
|
## Notes
|
|
201
226
|
|
|
202
227
|
- This skill only **documents** changes — it does not push or merge anything
|
|
203
|
-
- The
|
|
228
|
+
- The per-skill changelogs are consumed by the **downstream** skill in the
|
|
229
|
+
upstream monorepo
|
|
204
230
|
- Keep descriptions actionable: an upstream maintainer should be able to
|
|
205
231
|
understand and apply each change without access to this installation
|
|
206
232
|
- When in doubt about whether a change is upstream-worthy, include it — the
|