@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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forwardimpact/basecamp",
3
- "version": "2.3.0",
3
+ "version": "2.3.1",
4
4
  "description": "Claude Code-native personal knowledge system with autonomous agents",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -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. Finds threads with new messages since last sync (up to 500)
57
- 5. For each thread: fetches messages, batch-fetches recipients and attachment
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
- 6. Writes one markdown file per thread to `~/.cache/fit/basecamp/apple_mail/`
61
- 7. Updates sync state timestamp
62
- 8. Reports summary (threads processed, files written)
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** | Filename, email body, CV | Yes |
134
- | **Role** | Email body, CV | 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 |
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
- **Role:** {role title}
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/CHANGELOG.md` — structured changelog of all local skill changes
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/CHANGELOG.md 2>/dev/null
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/CHANGELOG.md` already exists, read the most recent entry date
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 `.claude/skills/`.
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
- Create or update `.claude/skills/CHANGELOG.md` with the following format:
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
- # Skill Changelog
115
+ # <skill-name> Changelog
113
116
 
114
- Changes to skills in this installation that should be considered for upstream
115
- inclusion in the Forward Impact monorepo.
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). Group changes
132
- from the same date under a single date heading.
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 Changelog
141
+ ### Step 5: Review the Changelogs
135
142
 
136
- After writing, read the changelog back and verify:
143
+ After writing, read each changelog back and verify:
137
144
 
138
- - [ ] Every changed skill has an entry
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
- # Skill Changelog
158
+ # track-candidates Changelog
150
159
 
151
- Changes to skills in this installation that should be considered for upstream
152
- inclusion in the Forward Impact monorepo.
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
- ### process-hyprnote (added)
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
- ## 2026-02-15
203
+ `.claude/skills/extract-entities/CHANGELOG.md`:
185
204
 
186
- ### extract-entities (modified)
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 changelog is consumed by the **downstream** skill in the upstream monorepo
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