@forwardimpact/outpost 3.0.3
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/LICENSE +201 -0
- package/README.md +15 -0
- package/bin/fit-outpost.js +3 -0
- package/config/scheduler.json +34 -0
- package/package.json +63 -0
- package/src/agent-runner.js +189 -0
- package/src/index.js +5 -0
- package/src/kb-manager.js +228 -0
- package/src/outpost.js +417 -0
- package/src/scheduler.js +195 -0
- package/src/socket-server.js +336 -0
- package/src/state-manager.js +126 -0
- package/templates/.claude/agents/chief-of-staff.md +58 -0
- package/templates/.claude/agents/concierge.md +46 -0
- package/templates/.claude/agents/head-hunter.md +57 -0
- package/templates/.claude/agents/librarian.md +60 -0
- package/templates/.claude/agents/postman.md +47 -0
- package/templates/.claude/agents/recruiter.md +63 -0
- package/templates/.claude/settings.json +88 -0
- package/templates/.claude/skills/candidate-report/SKILL.md +139 -0
- package/templates/.claude/skills/candidate-report/references/report-template.html +203 -0
- package/templates/.claude/skills/candidate-report/references/report.css +438 -0
- package/templates/.claude/skills/candidate-report/references/rubric.md +76 -0
- package/templates/.claude/skills/candidate-report/scripts/render-pdf.mjs +48 -0
- package/templates/.claude/skills/deck-create/SKILL.md +75 -0
- package/templates/.claude/skills/deck-create/references/slide.css +35 -0
- package/templates/.claude/skills/deck-create/scripts/convert-to-pdf.mjs +47 -0
- package/templates/.claude/skills/deck-summarize/SKILL.md +139 -0
- package/templates/.claude/skills/deck-summarize/references/brief-template.md +85 -0
- package/templates/.claude/skills/deck-summarize/scripts/extract-pptx.mjs +210 -0
- package/templates/.claude/skills/doc-collab/SKILL.md +112 -0
- package/templates/.claude/skills/doc-create/SKILL.md +105 -0
- package/templates/.claude/skills/doc-create/scripts/convert-to-pdf.mjs +50 -0
- package/templates/.claude/skills/draft-emails/SKILL.md +141 -0
- package/templates/.claude/skills/draft-emails/references/template.md +26 -0
- package/templates/.claude/skills/draft-emails/scripts/scan-emails.mjs +66 -0
- package/templates/.claude/skills/draft-emails/scripts/send-email.mjs +139 -0
- package/templates/.claude/skills/extract-entities/SKILL.md +187 -0
- package/templates/.claude/skills/extract-entities/references/TEMPLATES.md +14 -0
- package/templates/.claude/skills/extract-entities/references/conditions.md +55 -0
- package/templates/.claude/skills/extract-entities/references/content.md +104 -0
- package/templates/.claude/skills/extract-entities/references/links.md +48 -0
- package/templates/.claude/skills/extract-entities/references/recruitment.md +57 -0
- package/templates/.claude/skills/extract-entities/references/resolution.md +71 -0
- package/templates/.claude/skills/extract-entities/references/sources.md +70 -0
- package/templates/.claude/skills/extract-entities/references/templates-conditions.md +36 -0
- package/templates/.claude/skills/extract-entities/references/templates-goals-priorities.md +63 -0
- package/templates/.claude/skills/extract-entities/references/templates-people-orgs.md +67 -0
- package/templates/.claude/skills/extract-entities/references/templates-projects-topics.md +68 -0
- package/templates/.claude/skills/extract-entities/scripts/state.mjs +131 -0
- package/templates/.claude/skills/hyprnote-follow/SKILL.md +174 -0
- package/templates/.claude/skills/hyprnote-follow/references/coaching.md +118 -0
- package/templates/.claude/skills/hyprnote-follow/references/debrief.md +59 -0
- package/templates/.claude/skills/hyprnote-follow/references/meeting-types.md +14 -0
- package/templates/.claude/skills/hyprnote-follow/scripts/follow.mjs +243 -0
- package/templates/.claude/skills/hyprnote-process/SKILL.md +147 -0
- package/templates/.claude/skills/hyprnote-process/references/extraction.md +84 -0
- package/templates/.claude/skills/hyprnote-process/references/sessions.md +81 -0
- package/templates/.claude/skills/hyprnote-process/scripts/scan.mjs +246 -0
- package/templates/.claude/skills/hyprnote-trim/SKILL.md +177 -0
- package/templates/.claude/skills/manage-tasks/SKILL.md +152 -0
- package/templates/.claude/skills/manage-tasks/references/format.md +73 -0
- package/templates/.claude/skills/meeting-prep/SKILL.md +180 -0
- package/templates/.claude/skills/organize-files/SKILL.md +146 -0
- package/templates/.claude/skills/organize-files/scripts/organize-by-type.mjs +105 -0
- package/templates/.claude/skills/organize-files/scripts/summarize.mjs +91 -0
- package/templates/.claude/skills/req-assess/SKILL.md +137 -0
- package/templates/.claude/skills/req-assess/references/interview-template.md +62 -0
- package/templates/.claude/skills/req-assess/references/panel-template.md +117 -0
- package/templates/.claude/skills/req-assess/references/rubric.md +65 -0
- package/templates/.claude/skills/req-decide/SKILL.md +163 -0
- package/templates/.claude/skills/req-decide/references/rubric.md +63 -0
- package/templates/.claude/skills/req-decide/references/template.md +118 -0
- package/templates/.claude/skills/req-forget/SKILL.md +154 -0
- package/templates/.claude/skills/req-forget/references/classify.md +23 -0
- package/templates/.claude/skills/req-forget/references/locations.md +59 -0
- package/templates/.claude/skills/req-forget/references/report-template.md +67 -0
- package/templates/.claude/skills/req-scan/SKILL.md +145 -0
- package/templates/.claude/skills/req-scan/references/fallbacks.md +76 -0
- package/templates/.claude/skills/req-scan/references/filters.md +83 -0
- package/templates/.claude/skills/req-scan/references/sources.md +76 -0
- package/templates/.claude/skills/req-scan/references/state.md +54 -0
- package/templates/.claude/skills/req-scan/references/template.md +36 -0
- package/templates/.claude/skills/req-scan/scripts/state.mjs +396 -0
- package/templates/.claude/skills/req-screen/SKILL.md +151 -0
- package/templates/.claude/skills/req-screen/references/rubric.md +94 -0
- package/templates/.claude/skills/req-screen/references/template.md +91 -0
- package/templates/.claude/skills/req-track/SKILL.md +189 -0
- package/templates/.claude/skills/req-track/references/fields.md +114 -0
- package/templates/.claude/skills/req-track/references/signals.md +42 -0
- package/templates/.claude/skills/req-track/references/statuses.md +32 -0
- package/templates/.claude/skills/req-track/references/templates.md +127 -0
- package/templates/.claude/skills/req-workday/SKILL.md +162 -0
- package/templates/.claude/skills/req-workday/references/field-mapping.md +40 -0
- package/templates/.claude/skills/req-workday/references/status-mapping.md +38 -0
- package/templates/.claude/skills/req-workday/references/templates.md +126 -0
- package/templates/.claude/skills/req-workday/references/xlsx-format.md +56 -0
- package/templates/.claude/skills/req-workday/scripts/parse-workday.mjs +313 -0
- package/templates/.claude/skills/send-chat/SKILL.md +170 -0
- package/templates/.claude/skills/sync-apple-calendar/SKILL.md +145 -0
- package/templates/.claude/skills/sync-apple-calendar/references/SCHEMA.md +80 -0
- package/templates/.claude/skills/sync-apple-calendar/scripts/query.mjs +307 -0
- package/templates/.claude/skills/sync-apple-calendar/scripts/sync.mjs +332 -0
- package/templates/.claude/skills/sync-apple-mail/SKILL.md +151 -0
- package/templates/.claude/skills/sync-apple-mail/references/SCHEMA.md +115 -0
- package/templates/.claude/skills/sync-apple-mail/scripts/parse-emlx.mjs +389 -0
- package/templates/.claude/skills/sync-apple-mail/scripts/sync-helpers.mjs +372 -0
- package/templates/.claude/skills/sync-apple-mail/scripts/sync.mjs +239 -0
- package/templates/.claude/skills/sync-teams/SKILL.md +177 -0
- package/templates/.claude/skills/sync-teams/scripts/idb-reader.mjs +147 -0
- package/templates/.claude/skills/sync-teams/scripts/leveldb-reader.mjs +288 -0
- package/templates/.claude/skills/sync-teams/scripts/sync.mjs +381 -0
- package/templates/.claude/skills/upstream-skill/SKILL.md +130 -0
- package/templates/.claude/skills/upstream-skill/references/examples.md +80 -0
- package/templates/.claude/skills/weekly-update/SKILL.md +141 -0
- package/templates/.claude/skills/weekly-update/references/template.md +55 -0
- package/templates/CLAUDE.md +134 -0
- package/templates/USER.md +3 -0
- package/templates/apm.yml +5 -0
- package/templates/knowledge/Briefings/.gitkeep +0 -0
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: req-forget
|
|
3
|
+
description: >
|
|
4
|
+
Process GDPR Article 17 data erasure requests. Finds and removes all personal
|
|
5
|
+
data related to a named individual from the knowledge base, cached data, and
|
|
6
|
+
agent state files. Use when the user receives a right-to-be-forgotten
|
|
7
|
+
request, asks to delete all data about a person, or needs to comply with a
|
|
8
|
+
data erasure obligation.
|
|
9
|
+
compatibility: Requires macOS filesystem access
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Right to Be Forgotten
|
|
13
|
+
|
|
14
|
+
Process data erasure requests under GDPR Article 17. Given a person's name,
|
|
15
|
+
systematically find and remove all personal data from the knowledge base, cached
|
|
16
|
+
synced data, and agent state files. Produces an **erasure report** documenting
|
|
17
|
+
what was found, deleted, and redacted — the compliance audit trail.
|
|
18
|
+
|
|
19
|
+
## Trigger
|
|
20
|
+
|
|
21
|
+
- A formal GDPR erasure request arrives.
|
|
22
|
+
- The user asks to delete all data about a specific person.
|
|
23
|
+
- A candidate withdraws and requests data deletion.
|
|
24
|
+
- The user asks to "forget" someone.
|
|
25
|
+
|
|
26
|
+
## Prerequisites
|
|
27
|
+
|
|
28
|
+
- The person's full name (and any known aliases or email addresses).
|
|
29
|
+
- User confirmation before any deletion.
|
|
30
|
+
|
|
31
|
+
## Inputs
|
|
32
|
+
|
|
33
|
+
- **Name** (required) — full name of the data subject.
|
|
34
|
+
- **Aliases** (optional) — alternative names, maiden names, nicknames.
|
|
35
|
+
- **Emails** (optional) — improves search coverage.
|
|
36
|
+
- **Scope** — `all` (default) or `recruitment-only`.
|
|
37
|
+
|
|
38
|
+
## Outputs
|
|
39
|
+
|
|
40
|
+
- `knowledge/Erasure/{Name}--{YYYY-MM-DD}.md` — erasure report.
|
|
41
|
+
- Deleted files and redacted references across the knowledge base.
|
|
42
|
+
|
|
43
|
+
<do_confirm_checklist goal="Verify erasure is complete and the audit trail is
|
|
44
|
+
sound">
|
|
45
|
+
|
|
46
|
+
- [ ] User confirmed intent before any deletion.
|
|
47
|
+
- [ ] All discovery recipes ran; inventory covers knowledge, cache, state,
|
|
48
|
+
drafts.
|
|
49
|
+
- [ ] All dedicated files and directories deleted.
|
|
50
|
+
- [ ] All mentions and backlinks redacted from other notes.
|
|
51
|
+
- [ ] Cached email threads, attachments, and calendar entries handled.
|
|
52
|
+
- [ ] Agent state and `graph_processed` cleaned.
|
|
53
|
+
- [ ] Erasure report saved; contains **no** personal data beyond the name and
|
|
54
|
+
actions taken.
|
|
55
|
+
- [ ] Final `rg` search shows only the erasure report as a match.
|
|
56
|
+
|
|
57
|
+
</do_confirm_checklist>
|
|
58
|
+
|
|
59
|
+
## Procedure
|
|
60
|
+
|
|
61
|
+
### 0. Confirm intent
|
|
62
|
+
|
|
63
|
+
State to the user:
|
|
64
|
+
|
|
65
|
+
> **Data erasure request for: {Name}**
|
|
66
|
+
>
|
|
67
|
+
> This will permanently delete all personal data related to {Name} from:
|
|
68
|
+
>
|
|
69
|
+
> - Knowledge base notes (People, Candidates, Organizations mentions)
|
|
70
|
+
> - Cached email threads and attachments
|
|
71
|
+
> - Agent state and triage files
|
|
72
|
+
>
|
|
73
|
+
> This action cannot be undone. Proceed?
|
|
74
|
+
|
|
75
|
+
**Wait for explicit confirmation before continuing.**
|
|
76
|
+
|
|
77
|
+
### 1. Discovery
|
|
78
|
+
|
|
79
|
+
Run every recipe in [references/locations.md](references/locations.md) and
|
|
80
|
+
compile a complete inventory of every file and reference found.
|
|
81
|
+
|
|
82
|
+
### 2. Classify
|
|
83
|
+
|
|
84
|
+
For each match, pick an action from the table in
|
|
85
|
+
[references/classify.md](references/classify.md). Apply its redaction rules
|
|
86
|
+
where redaction is the action.
|
|
87
|
+
|
|
88
|
+
### 3. Execute deletions
|
|
89
|
+
|
|
90
|
+
Process most-specific to most-general.
|
|
91
|
+
|
|
92
|
+
**3a. Dedicated files and directories:**
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
rm -rf "knowledge/Candidates/{Name}/"
|
|
96
|
+
rm -f "knowledge/People/{Name}.md"
|
|
97
|
+
find ~/.cache/fit/outpost/apple_mail/attachments/ -iname "*{Name}*" -delete
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
**3b. Redact mentions in other notes:** read each file, remove the specific
|
|
101
|
+
lines/bullets/sections per the rules in
|
|
102
|
+
[references/classify.md](references/classify.md#redaction-rules), remove broken
|
|
103
|
+
`[[backlinks]]` to deleted notes, write the file back.
|
|
104
|
+
|
|
105
|
+
**3c. Email threads:** delete sole-subject threads; redact paragraphs only in
|
|
106
|
+
multi-person threads.
|
|
107
|
+
|
|
108
|
+
**3d. Agent state files:**
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
for f in ~/.cache/fit/outpost/state/*_triage.md; do
|
|
112
|
+
if rg -q "{Name}" "$f" 2>/dev/null; then
|
|
113
|
+
rg -v "{Name}" "$f" > "$f.tmp" && mv "$f.tmp" "$f"
|
|
114
|
+
fi
|
|
115
|
+
done
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**3e. Processing state:** drop deleted paths from `graph_processed`:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
rg -v "{deleted_path}" ~/.cache/fit/outpost/state/graph_processed \
|
|
122
|
+
> ~/.cache/fit/outpost/state/graph_processed.tmp \
|
|
123
|
+
&& mv ~/.cache/fit/outpost/state/graph_processed.tmp \
|
|
124
|
+
~/.cache/fit/outpost/state/graph_processed
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### 4. Write the erasure report
|
|
128
|
+
|
|
129
|
+
Save to `knowledge/Erasure/{Name}--{YYYY-MM-DD}.md` using the template in
|
|
130
|
+
[references/report-template.md](references/report-template.md). Record **only**
|
|
131
|
+
what was deleted — never CV content, skills, or assessments.
|
|
132
|
+
|
|
133
|
+
### 5. Verify
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
rg "{Name}" knowledge/ ~/.cache/fit/outpost/ drafts/
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
The only match should be the erasure report. If other matches remain, process
|
|
140
|
+
them and update the report.
|
|
141
|
+
|
|
142
|
+
## Scope variants
|
|
143
|
+
|
|
144
|
+
**`recruitment-only`** limits erasure to:
|
|
145
|
+
|
|
146
|
+
- `knowledge/Candidates/{Name}/`
|
|
147
|
+
- `knowledge/Candidates/Insights.md` mentions
|
|
148
|
+
- Recruitment threads (known agency domains)
|
|
149
|
+
- `recruiter_triage.md`
|
|
150
|
+
|
|
151
|
+
Leaves `knowledge/People/{Name}.md` and the wider graph intact — the person may
|
|
152
|
+
be a colleague or non-recruitment contact.
|
|
153
|
+
|
|
154
|
+
**`all`** (default): full erasure across knowledge base, cache, and state.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Reference Classification
|
|
2
|
+
|
|
3
|
+
Reference for `req-forget` Step 2. For every match in the inventory, pick the
|
|
4
|
+
action below.
|
|
5
|
+
|
|
6
|
+
| Reference Type | Action | Example |
|
|
7
|
+
| ---------------------------------- | ------------------------------------------- | ----------------------------------------------- |
|
|
8
|
+
| **Dedicated note** (sole subject) | Delete entire file | `knowledge/People/{Name}.md` |
|
|
9
|
+
| **Dedicated directory** | Delete entire directory | `knowledge/Candidates/{Name}/` |
|
|
10
|
+
| **Mention in another note** | Redact: remove lines referencing the person | Backlink in `knowledge/Organizations/Agency.md` |
|
|
11
|
+
| **Email thread** (sole subject) | Delete file | `~/.cache/fit/outpost/apple_mail/thread.md` |
|
|
12
|
+
| **Email thread** (multiple people) | Redact: remove paragraphs about the person | Thread discussing multiple candidates |
|
|
13
|
+
| **Attachment** (their CV, etc.) | Delete file | `attachments/{thread}/CV.pdf` |
|
|
14
|
+
| **Triage/state file** | Redact: remove lines mentioning them | `recruiter_triage.md` |
|
|
15
|
+
| **Insights file** | Redact: remove bullets mentioning them | `knowledge/Candidates/Insights.md` |
|
|
16
|
+
|
|
17
|
+
## Redaction rules
|
|
18
|
+
|
|
19
|
+
- Remove entire bullet points that mention the person by name.
|
|
20
|
+
- Remove table rows containing the person's name.
|
|
21
|
+
- Remove `## Connected to` entries linking to deleted notes.
|
|
22
|
+
- If a section becomes empty after redaction, remove its header too.
|
|
23
|
+
- Do **not** remove surrounding context that doesn't identify the person.
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Discovery Search Recipes
|
|
2
|
+
|
|
3
|
+
Reference for `req-forget` Step 1. Run every recipe; record every match into the
|
|
4
|
+
inventory.
|
|
5
|
+
|
|
6
|
+
## Knowledge base — direct notes
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
ls -d "knowledge/Candidates/{Name}/" 2>/dev/null
|
|
10
|
+
ls "knowledge/People/{Name}.md" 2>/dev/null
|
|
11
|
+
|
|
12
|
+
# Common name variations
|
|
13
|
+
ls "knowledge/People/{First} {Last}.md" 2>/dev/null
|
|
14
|
+
ls "knowledge/People/{Last}, {First}.md" 2>/dev/null
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Knowledge base — backlinks and mentions
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
rg -l "{Name}" knowledge/
|
|
21
|
+
rg -l "{First name} {Last name}" knowledge/
|
|
22
|
+
rg -l "\[\[.*{Name}.*\]\]" knowledge/
|
|
23
|
+
rg -l "{email}" knowledge/
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Cached email threads
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
rg -l "{Name}" ~/.cache/fit/outpost/apple_mail/ 2>/dev/null
|
|
30
|
+
rg -l "{email}" ~/.cache/fit/outpost/apple_mail/ 2>/dev/null
|
|
31
|
+
find ~/.cache/fit/outpost/apple_mail/attachments/ -iname "*{Name}*" 2>/dev/null
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Cached calendar events
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
rg -l "{Name}" ~/.cache/fit/outpost/apple_calendar/ 2>/dev/null
|
|
38
|
+
rg -l "{email}" ~/.cache/fit/outpost/apple_calendar/ 2>/dev/null
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Agent state files
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
rg -l "{Name}" ~/.cache/fit/outpost/state/ 2>/dev/null
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Drafts
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
rg -l "{Name}" drafts/ 2>/dev/null
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Final verification
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
rg "{Name}" knowledge/ ~/.cache/fit/outpost/ drafts/
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
Expected: only the erasure report matches.
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Erasure Report Template
|
|
2
|
+
|
|
3
|
+
Audit trail for `req-forget` Step 4. Save to
|
|
4
|
+
`knowledge/Erasure/{Name}--{YYYY-MM-DD}.md`.
|
|
5
|
+
|
|
6
|
+
**The report itself must not contain personal data** beyond the subject's name
|
|
7
|
+
and the actions taken. Do not copy CV content, skills, or assessments into the
|
|
8
|
+
report — record only what was deleted, not what it contained.
|
|
9
|
+
|
|
10
|
+
````markdown
|
|
11
|
+
# Data Erasure Report — {Full Name}
|
|
12
|
+
|
|
13
|
+
**Date:** {YYYY-MM-DD HH:MM}
|
|
14
|
+
**Requested by:** {user or "GDPR Article 17 request"}
|
|
15
|
+
**Scope:** {all / recruitment-only}
|
|
16
|
+
|
|
17
|
+
## Data Subject
|
|
18
|
+
- **Name:** {Full Name}
|
|
19
|
+
- **Known aliases:** {aliases or "none"}
|
|
20
|
+
- **Known emails:** {emails or "none"}
|
|
21
|
+
|
|
22
|
+
## Actions Taken
|
|
23
|
+
|
|
24
|
+
### Deleted Files
|
|
25
|
+
- `knowledge/Candidates/{Name}/brief.md`
|
|
26
|
+
- `knowledge/Candidates/{Name}/CV.pdf`
|
|
27
|
+
- `knowledge/Candidates/{Name}/screening.md`
|
|
28
|
+
- `knowledge/People/{Name}.md`
|
|
29
|
+
- {list all deleted files}
|
|
30
|
+
|
|
31
|
+
### Redacted References
|
|
32
|
+
- `knowledge/Organizations/{Agency}.md` — removed backlink
|
|
33
|
+
- `knowledge/Candidates/Insights.md` — removed {N} bullet(s)
|
|
34
|
+
- {list all redacted files and what was removed}
|
|
35
|
+
|
|
36
|
+
### Cached Data Removed
|
|
37
|
+
- `~/.cache/fit/outpost/apple_mail/{thread}.md` — deleted (sole subject)
|
|
38
|
+
- `~/.cache/fit/outpost/apple_mail/{thread2}.md` — redacted (multi-person)
|
|
39
|
+
- {list all cache actions}
|
|
40
|
+
|
|
41
|
+
### State Files Cleaned
|
|
42
|
+
- `~/.cache/fit/outpost/state/recruiter_triage.md` — redacted
|
|
43
|
+
- {list all state file actions}
|
|
44
|
+
|
|
45
|
+
## Requires Manual Action
|
|
46
|
+
|
|
47
|
+
The following are outside this tool's reach:
|
|
48
|
+
|
|
49
|
+
- **Apple Mail** — original emails remain in the user's mailbox. Search
|
|
50
|
+
Mail.app for "{Name}" and delete threads manually.
|
|
51
|
+
- **Apple Calendar** — events remain in Calendar.app.
|
|
52
|
+
- **Recruitment agencies** — notify {Agency} of the deletion and request
|
|
53
|
+
they do the same.
|
|
54
|
+
- **Interview notes** — check physical notebooks and external apps.
|
|
55
|
+
- **Shared documents** — check Google Drive, SharePoint, etc.
|
|
56
|
+
|
|
57
|
+
## Verification
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
rg "{Name}" knowledge/ ~/.cache/fit/outpost/
|
|
61
|
+
````
|
|
62
|
+
|
|
63
|
+
Expected: no matches except this erasure report.
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
```
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: req-scan
|
|
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/outpost/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 fetching,
|
|
15
|
+
filtering, deduplication, benchmarking, prospect-note writing, and memory
|
|
16
|
+
updates.
|
|
17
|
+
|
|
18
|
+
## Trigger
|
|
19
|
+
|
|
20
|
+
- The head-hunter agent is woken by the scheduler.
|
|
21
|
+
- The user asks to scan for open candidates or prospects.
|
|
22
|
+
|
|
23
|
+
## Prerequisites
|
|
24
|
+
|
|
25
|
+
- `WebFetch` tool available (Claude Code built-in — no curl/wget).
|
|
26
|
+
- `fit-pathway` CLI available (`bunx fit-pathway`).
|
|
27
|
+
- Memory directory `~/.cache/fit/outpost/head-hunter/`.
|
|
28
|
+
|
|
29
|
+
## Inputs
|
|
30
|
+
|
|
31
|
+
- `~/.cache/fit/outpost/head-hunter/cursor.tsv` — source rotation.
|
|
32
|
+
- `~/.cache/fit/outpost/head-hunter/seen.tsv` — deduplication.
|
|
33
|
+
- Standard data via `bunx fit-pathway skill --list` and `bunx fit-pathway job`.
|
|
34
|
+
|
|
35
|
+
## Outputs
|
|
36
|
+
|
|
37
|
+
- `knowledge/Prospects/{Name}.md`.
|
|
38
|
+
- Updated `cursor.tsv`, `seen.tsv`, `prospects.tsv`, and `log.md`.
|
|
39
|
+
- `~/.cache/fit/outpost/state/head_hunter_triage.md`.
|
|
40
|
+
|
|
41
|
+
<do_confirm_checklist goal="Verify the wake produced a clean, ethical scan">
|
|
42
|
+
|
|
43
|
+
- [ ] Selected the least-recently-checked, non-suspended source.
|
|
44
|
+
- [ ] Fetched via `WebFetch` (never curl/wget).
|
|
45
|
+
- [ ] Applied all 5 filters in order; passed candidates have ≥ 2
|
|
46
|
+
standard-relevant skills.
|
|
47
|
+
- [ ] Deduplicated against `seen.tsv` before processing.
|
|
48
|
+
- [ ] Benchmarked each prospect against a real `bunx fit-pathway job`.
|
|
49
|
+
- [ ] Prospect notes follow the template (no fabricated names).
|
|
50
|
+
- [ ] All state mutations went through `node scripts/state.mjs` — cursor, seen,
|
|
51
|
+
prospects, failures, log.
|
|
52
|
+
- [ ] Triage report written to the state directory; alternative queries (if any)
|
|
53
|
+
logged.
|
|
54
|
+
- [ ] Failures recorded; sources with ≥ 3 consecutive failures suspended.
|
|
55
|
+
|
|
56
|
+
</do_confirm_checklist>
|
|
57
|
+
|
|
58
|
+
## Procedure
|
|
59
|
+
|
|
60
|
+
### 1. Pick a source
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
node scripts/state.mjs cursor list
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Pick the least-recently-checked source. Skip suspended sources (`failure get` ≥
|
|
67
|
+
3). If all are suspended, report it in the triage and exit. Source URLs and
|
|
68
|
+
parse fields: [references/sources.md](references/sources.md).
|
|
69
|
+
|
|
70
|
+
### 2. Fetch and scan
|
|
71
|
+
|
|
72
|
+
Use `WebFetch` per [references/sources.md](references/sources.md). On failure,
|
|
73
|
+
follow [references/filters.md](references/filters.md#failure-handling).
|
|
74
|
+
|
|
75
|
+
### 3. Filter
|
|
76
|
+
|
|
77
|
+
Apply the 5-filter pipeline in
|
|
78
|
+
[references/filters.md](references/filters.md#filter-pipeline) — signal, dedup,
|
|
79
|
+
geographic, skill alignment, experience level.
|
|
80
|
+
|
|
81
|
+
### 3b. Fallback — zero new prospects
|
|
82
|
+
|
|
83
|
+
If filtering eliminates every candidate, try up to **3 alternatives** per wake
|
|
84
|
+
from [references/fallbacks.md](references/fallbacks.md). Log every alternative
|
|
85
|
+
in `log.md`.
|
|
86
|
+
|
|
87
|
+
### 4. Benchmark and write prospect notes
|
|
88
|
+
|
|
89
|
+
For each candidate that passes filters, benchmark:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
bunx fit-pathway job {discipline} {estimated_level} --track={best_track}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Classify match strength:
|
|
96
|
+
|
|
97
|
+
- **strong** — multiple core skills match, level aligns, location works, plus
|
|
98
|
+
non-traditional signals for forward-deployed.
|
|
99
|
+
- **moderate** — some overlap, level roughly right, minor gaps.
|
|
100
|
+
- **weak** — few matching signals, significant gaps.
|
|
101
|
+
|
|
102
|
+
Write notes for **strong** and **moderate** matches only, using the template in
|
|
103
|
+
[references/template.md](references/template.md).
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
mkdir -p "knowledge/Prospects"
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### 5. Update state
|
|
110
|
+
|
|
111
|
+
All state changes go through `node scripts/state.mjs` — full command reference:
|
|
112
|
+
[references/state.md](references/state.md). Each wake:
|
|
113
|
+
|
|
114
|
+
1. Update the cursor (`cursor set`).
|
|
115
|
+
2. Reset failure count on success or increment on failure.
|
|
116
|
+
3. Append every processed post ID to `seen` (`seen batch` for many).
|
|
117
|
+
4. Add new prospects (`prospect add`).
|
|
118
|
+
5. Append the wake summary (`log-wake`).
|
|
119
|
+
|
|
120
|
+
### 6. Write the triage report
|
|
121
|
+
|
|
122
|
+
Save to `~/.cache/fit/outpost/state/head_hunter_triage.md`:
|
|
123
|
+
|
|
124
|
+
```markdown
|
|
125
|
+
# Head Hunter Triage — {YYYY-MM-DD HH:MM}
|
|
126
|
+
|
|
127
|
+
## Last Scan
|
|
128
|
+
Source: {source_id} ({description})
|
|
129
|
+
Posts scanned: {N}
|
|
130
|
+
New prospects: {N}
|
|
131
|
+
Skipped: {N} (dedup: {N}, location: {N}, skill fit: {N})
|
|
132
|
+
Alternative queries tried: {N} ({list, or "none needed"})
|
|
133
|
+
|
|
134
|
+
## Pipeline Summary
|
|
135
|
+
Total prospects: {N} (strong: {N}, moderate: {N})
|
|
136
|
+
Sources checked today: {list}
|
|
137
|
+
Oldest unchecked source: {source_id} (last: {date})
|
|
138
|
+
Suspended sources: {list with failure counts, or "none"}
|
|
139
|
+
|
|
140
|
+
## Recent Prospects
|
|
141
|
+
- **{Name}** — {match_strength}, {estimated_level} {track}, {location}
|
|
142
|
+
|
|
143
|
+
## Retention
|
|
144
|
+
{List prospects older than 90 days not acted on, if any.}
|
|
145
|
+
```
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Fallback Strategies
|
|
2
|
+
|
|
3
|
+
Reference for `req-scan` when a primary source query yields zero new prospects
|
|
4
|
+
after filtering. Try at most **3 alternatives per wake** to stay within rate
|
|
5
|
+
limits.
|
|
6
|
+
|
|
7
|
+
## Strategy 1 — alternative search terms
|
|
8
|
+
|
|
9
|
+
### HN
|
|
10
|
+
|
|
11
|
+
- Check the **previous** month's "Who Wants to Be Hired?" thread.
|
|
12
|
+
- Search for `"Who is hiring"` threads (candidates sometimes post in the wrong
|
|
13
|
+
thread; comments may link to candidate profiles).
|
|
14
|
+
- Try
|
|
15
|
+
`https://hn.algolia.com/api/v1/search?query=%22freelancer+available%22&tags=comment`.
|
|
16
|
+
|
|
17
|
+
### GitHub
|
|
18
|
+
|
|
19
|
+
Search by skill + availability:
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
WebFetch URL: https://api.github.com/search/users?q=%22data+engineering%22+%22open+to+work%22&per_page=30&sort=joined&order=desc
|
|
23
|
+
WebFetch URL: https://api.github.com/search/users?q=%22full+stack%22+%22available+for+hire%22&per_page=30&sort=joined&order=desc
|
|
24
|
+
WebFetch URL: https://api.github.com/search/users?q=%22devops%22+%22looking+for%22&per_page=30&sort=joined&order=desc
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Search repos with README signals:
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
WebFetch URL: https://api.github.com/search/repositories?q=%22hire+me%22+in:readme&sort=updated&order=desc&per_page=10
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Try alternate location terms: Greece, Athens, Warsaw, Bucharest, Sofia,
|
|
34
|
+
Manchester, Edinburgh.
|
|
35
|
+
|
|
36
|
+
### dev.to
|
|
37
|
+
|
|
38
|
+
Try broader tags: `jobsearch`, `career`, `remotework`, `job`, `hiring`. Or pull
|
|
39
|
+
from a tag and filter by title/description:
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
WebFetch URL: https://dev.to/api/articles?tag=career&per_page=25
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Strategy 2 — relax filters
|
|
46
|
+
|
|
47
|
+
If geography eliminated everyone, re-scan without the location filter. Mark
|
|
48
|
+
unmatched-location prospects as "location unconfirmed" in the prospect note.
|
|
49
|
+
|
|
50
|
+
If skill alignment filtered everyone out: lower the bar from 2 standard skills
|
|
51
|
+
to 1; consider transferable skills (strong Python ⇒ likely data integration
|
|
52
|
+
capability); accept adjacent indicators ("machine learning" implies data
|
|
53
|
+
skills).
|
|
54
|
+
|
|
55
|
+
## Strategy 3 — cross-reference
|
|
56
|
+
|
|
57
|
+
When a source yields very few results, enrich what you do find:
|
|
58
|
+
|
|
59
|
+
- A GitHub profile that links to a blog/portfolio → WebFetch it for more detail
|
|
60
|
+
before deciding skill fit.
|
|
61
|
+
- An HN post that mentions a GitHub username → fetch their GitHub profile for
|
|
62
|
+
richer signal.
|
|
63
|
+
|
|
64
|
+
## Logging alternatives
|
|
65
|
+
|
|
66
|
+
Log every alternative in `log.md`:
|
|
67
|
+
|
|
68
|
+
```markdown
|
|
69
|
+
## 2026-03-05 14:00
|
|
70
|
+
|
|
71
|
+
Source: github_open_to_work
|
|
72
|
+
Primary query: "open to work" location:UK — 30 results, 0 new after dedup
|
|
73
|
+
Alternative 1: "data engineering" "open to work" — 12 results, 1 new prospect
|
|
74
|
+
Alternative 2: "full stack" "available for hire" — 8 results, 0 new
|
|
75
|
+
Stopped after 2 alternatives (1 prospect found)
|
|
76
|
+
```
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# Filter Pipeline & Failure Handling
|
|
2
|
+
|
|
3
|
+
Reference for `req-scan` Steps 3 (filter) and 5 (failure handling).
|
|
4
|
+
|
|
5
|
+
## Filter pipeline
|
|
6
|
+
|
|
7
|
+
Apply in order. Stop at the first that excludes the candidate.
|
|
8
|
+
|
|
9
|
+
### 1. Open-for-hire signal
|
|
10
|
+
|
|
11
|
+
- HN "Who Wants to Be Hired?" → **auto-pass** (thread is opt-in).
|
|
12
|
+
- GitHub → must have `hireable: true` **or** bio contains an open-to-work
|
|
13
|
+
phrase.
|
|
14
|
+
- dev.to → must be tagged `opentowork` or `lookingforwork`.
|
|
15
|
+
|
|
16
|
+
### 2. Deduplication
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
node scripts/state.mjs seen check {source} {post_id}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
If exit 0 (seen), skip. Otherwise continue.
|
|
23
|
+
|
|
24
|
+
### 3. Geographic fit
|
|
25
|
+
|
|
26
|
+
Prefer or accept candidates in or open to:
|
|
27
|
+
|
|
28
|
+
- **US East Coast** (NYC, Boston, DC, Philadelphia, …).
|
|
29
|
+
- **UK** (London, Manchester, Edinburgh, …).
|
|
30
|
+
- **EU** — especially Greece, Poland, Romania, Bulgaria.
|
|
31
|
+
- **Remote / Anywhere / Global**.
|
|
32
|
+
|
|
33
|
+
Skip candidates explicitly locked to incompatible regions ("San Francisco only",
|
|
34
|
+
"APAC only"). When location is ambiguous or unstated, include the candidate —
|
|
35
|
+
let the user decide.
|
|
36
|
+
|
|
37
|
+
### 4. Skill alignment
|
|
38
|
+
|
|
39
|
+
`bunx fit-pathway skill --list` for the standard inventory. Strong signals:
|
|
40
|
+
|
|
41
|
+
**Forward Deployed:** multiple industries / domains, customer-facing projects,
|
|
42
|
+
data integration / analytics / visualization, full-stack with business context,
|
|
43
|
+
non-traditional path (law, policy, academia → tech), AI/ML tool proficiency
|
|
44
|
+
(Claude, GPT, Cursor, "vibe coding").
|
|
45
|
+
|
|
46
|
+
**Platform:** infrastructure / cloud / DevOps, architecture and system design,
|
|
47
|
+
API design and shared services, performance / scalability / reliability.
|
|
48
|
+
|
|
49
|
+
**Minimum bar:** at least 2 standard-relevant skills must be identifiable from
|
|
50
|
+
the post. Skip candidates with purely non-technical profiles.
|
|
51
|
+
|
|
52
|
+
### 5. Experience level
|
|
53
|
+
|
|
54
|
+
| Signal | Likely level |
|
|
55
|
+
| ------------------------------------------- | ------------ |
|
|
56
|
+
| "junior", "entry-level", 0–2 years | J040 |
|
|
57
|
+
| "mid-level", 3–5 years | J060 |
|
|
58
|
+
| "senior", 5–8 years, "lead" | J070 |
|
|
59
|
+
| "staff", "principal", 8+ years, "architect" | J090+ |
|
|
60
|
+
|
|
61
|
+
When uncertain, default to J060 with low confidence.
|
|
62
|
+
|
|
63
|
+
## Failure handling
|
|
64
|
+
|
|
65
|
+
When a WebFetch fails (HTTP 4xx, 5xx, timeout, empty response, redirect to a
|
|
66
|
+
block page):
|
|
67
|
+
|
|
68
|
+
1. Increment the failure count:
|
|
69
|
+
`node scripts/state.mjs failure increment {source}`.
|
|
70
|
+
2. **Do not retry** the same source in this wake cycle.
|
|
71
|
+
3. Suspend after 3 consecutive failures — skip during source selection. Retry
|
|
72
|
+
suspended sources once every 7 days to detect recovery.
|
|
73
|
+
4. Log the failure in `log.md` with HTTP status and error.
|
|
74
|
+
5. Reset on success: `node scripts/state.mjs failure reset {source}`.
|
|
75
|
+
|
|
76
|
+
### Common failure patterns
|
|
77
|
+
|
|
78
|
+
| Symptom | Likely cause |
|
|
79
|
+
| ------------------------ | ------------------------------------------------------ |
|
|
80
|
+
| 503 with HTML redirect | Corporate proxy blocking the domain (won't recover) |
|
|
81
|
+
| 403 Forbidden | Auth required or automated requests blocked |
|
|
82
|
+
| 429 Too Many Requests | Rate limited — will recover; don't suspend permanently |
|
|
83
|
+
| Empty response / timeout | Transient — likely recovers next wake |
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# Sources
|
|
2
|
+
|
|
3
|
+
Reference for `req-scan` Step 2 (fetch & scan). One source per wake cycle.
|
|
4
|
+
|
|
5
|
+
## 1. Hacker News "Who Wants to Be Hired?"
|
|
6
|
+
|
|
7
|
+
Monthly thread, posted on the 1st.
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
WebFetch URL: https://hn.algolia.com/api/v1/search?query=%22Who+wants+to+be+hired%22&tags=ask_hn&hitsPerPage=5
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The first hit whose title matches "Who wants to be hired?" with `created_at` in
|
|
14
|
+
the current or previous month is the target thread.
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
WebFetch URL: https://hn.algolia.com/api/v1/items/{objectID}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
`children[]` contains top-level comments — each is one candidate. Parse the
|
|
21
|
+
`text` field for:
|
|
22
|
+
|
|
23
|
+
- **Location** ("Location: New York", "NYC / Remote").
|
|
24
|
+
- **Remote** ("Remote: Yes", "Open to remote").
|
|
25
|
+
- **Skills** — tech stack, language/standard mentions.
|
|
26
|
+
- **Experience** — years, role titles, past companies.
|
|
27
|
+
- **Contact** — email (often obfuscated: "name [at] domain [dot] com").
|
|
28
|
+
- **Resume / CV** — links to personal sites, GitHub, LinkedIn.
|
|
29
|
+
|
|
30
|
+
**Cursor:** thread `objectID` plus the ID of the last processed child comment.
|
|
31
|
+
**Rate:** no strict limit; one fetch per wake cycle.
|
|
32
|
+
|
|
33
|
+
## 2. GitHub Open to Work
|
|
34
|
+
|
|
35
|
+
Search by location (rotate one query per wake):
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
WebFetch URL: https://api.github.com/search/users?q=%22open+to+work%22+location:UK&per_page=30&sort=joined&order=desc
|
|
39
|
+
WebFetch URL: https://api.github.com/search/users?q=%22open+to+work%22+location:Europe&per_page=30&sort=joined&order=desc
|
|
40
|
+
WebFetch URL: https://api.github.com/search/users?q=%22looking+for+work%22+location:remote&per_page=30&sort=joined&order=desc
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Alternate bio phrases to rotate across wakes: `"available for hire"`,
|
|
44
|
+
`"seeking opportunities"`, `"seeking new role"`, `"open to new opportunities"`,
|
|
45
|
+
`"currently exploring"`, `"freelance" "available"`, `"between roles"`,
|
|
46
|
+
`"on the market"`, `"open to opportunities"`.
|
|
47
|
+
|
|
48
|
+
Fetch each promising candidate's full profile:
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
WebFetch URL: https://api.github.com/users/{login}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Profile fields: `name`, `bio`, `location`, `hireable`, `blog`, `company` (null =
|
|
55
|
+
likely available), `public_repos`, `created_at`.
|
|
56
|
+
|
|
57
|
+
**Cursor:** location query last used + page number. Rotate UK → Europe → Remote
|
|
58
|
+
→ repeat. **Rate:** 10 requests/min unauthenticated. Fetch at most 5 full
|
|
59
|
+
profiles per wake (1 search + 5 profile fetches = 6 requests).
|
|
60
|
+
|
|
61
|
+
## 3. dev.to
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
WebFetch URL: https://dev.to/api/articles?tag=opentowork&per_page=25
|
|
65
|
+
WebFetch URL: https://dev.to/api/articles?tag=lookingforwork&per_page=25
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Fields: `title`, `description`, `user.name`, `user.username`, `url`, `tag_list`,
|
|
69
|
+
`published_at`. Skip articles older than 90 days.
|
|
70
|
+
|
|
71
|
+
**Cursor:** `id` of the most recent article processed. **Rate:** 30 req per 30
|
|
72
|
+
s. One fetch per wake.
|
|
73
|
+
|
|
74
|
+
## Use WebFetch only
|
|
75
|
+
|
|
76
|
+
**Never use `curl` or `wget`.** WebFetch is the supported transport.
|