job-forge 2.0.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/.codex/config.toml +8 -0
- package/.cursor/mcp.json +21 -0
- package/.cursor/rules/main.mdc +519 -0
- package/.mcp.json +21 -0
- package/.opencode/agents/general-free.md +85 -0
- package/.opencode/agents/general-paid.md +39 -0
- package/.opencode/agents/glm-minimal.md +50 -0
- package/.opencode/skills/job-forge.md +185 -0
- package/AGENTS.md +514 -0
- package/CLAUDE.md +514 -0
- package/LICENSE +21 -0
- package/README.md +195 -0
- package/batch/README.md +60 -0
- package/batch/batch-prompt.md +399 -0
- package/batch/batch-runner.sh +673 -0
- package/bin/create-job-forge.mjs +375 -0
- package/bin/job-forge.mjs +120 -0
- package/bin/sync.mjs +141 -0
- package/config/profile.example.yml +67 -0
- package/cv-sync-check.mjs +128 -0
- package/dedup-tracker.mjs +201 -0
- package/docs/ARCHITECTURE.md +220 -0
- package/docs/CUSTOMIZATION.md +101 -0
- package/docs/MODEL-ROUTING.md +195 -0
- package/docs/README.md +54 -0
- package/docs/SETUP.md +186 -0
- package/docs/demo.gif +0 -0
- package/fonts/dm-sans-latin-ext.woff2 +0 -0
- package/fonts/dm-sans-latin.woff2 +0 -0
- package/fonts/space-grotesk-latin-ext.woff2 +0 -0
- package/fonts/space-grotesk-latin.woff2 +0 -0
- package/generate-pdf.mjs +168 -0
- package/iso/agents/general-free.md +90 -0
- package/iso/agents/general-paid.md +44 -0
- package/iso/agents/glm-minimal.md +55 -0
- package/iso/commands/job-forge.md +188 -0
- package/iso/config.json +7 -0
- package/iso/instructions.md +514 -0
- package/iso/mcp.json +15 -0
- package/merge-tracker.mjs +377 -0
- package/modes/README.md +30 -0
- package/modes/_shared-calibration.md +26 -0
- package/modes/_shared.md +272 -0
- package/modes/apply.md +257 -0
- package/modes/auto-pipeline.md +70 -0
- package/modes/batch.md +110 -0
- package/modes/compare.md +23 -0
- package/modes/contact.md +82 -0
- package/modes/deep.md +99 -0
- package/modes/followup.md +68 -0
- package/modes/negotiation.md +146 -0
- package/modes/offer.md +199 -0
- package/modes/pdf.md +121 -0
- package/modes/pipeline.md +83 -0
- package/modes/project.md +30 -0
- package/modes/rejection.md +92 -0
- package/modes/scan.md +185 -0
- package/modes/tracker.md +31 -0
- package/modes/training.md +27 -0
- package/normalize-statuses.mjs +152 -0
- package/opencode.json +28 -0
- package/package.json +78 -0
- package/scripts/add-tags.mjs +894 -0
- package/scripts/cursor-agent-loop.sh +211 -0
- package/scripts/cursor-agent-stream-format.py +134 -0
- package/scripts/next-num.mjs +33 -0
- package/scripts/release/check-source.mjs +37 -0
- package/scripts/render-report-header.mjs +78 -0
- package/scripts/session-report.mjs +129 -0
- package/scripts/slugify.mjs +27 -0
- package/scripts/today.mjs +20 -0
- package/scripts/token-usage-report.mjs +315 -0
- package/scripts/tracker-line.mjs +67 -0
- package/scripts/verify-greenhouse-urls.mjs +195 -0
- package/templates/cv-template.html +395 -0
- package/templates/portals.example.yml +3140 -0
- package/templates/states.yml +62 -0
- package/tracker-lib.mjs +257 -0
- package/verify-pipeline.mjs +267 -0
package/modes/batch.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# Mode: batch — Bulk Offer Processing
|
|
2
|
+
|
|
3
|
+
Two usage modes: **conductor** (navigates portals in real time via Geometra MCP) or **standalone** (script for already-collected URLs).
|
|
4
|
+
|
|
5
|
+
## Apply The Session-Length Rule
|
|
6
|
+
|
|
7
|
+
**Never run `batch` as one long interactive session.** Each offer gets its own `opencode run` worker via `batch-runner.sh` — that's the whole point of the architecture. Workers have clean ~200K-token contexts and exit after producing one report + PDF + tracker line, so prompt caching stays healthy.
|
|
8
|
+
|
|
9
|
+
If you find yourself doing `geometra_fill_form` or `geometra_page_model` for the Nth time in the *same* session, stop and delegate. See "Session Hygiene" in `.opencode/skills/job-forge.md` for the full rationale (cache-bust behavior with repeated Geometra tool calls).
|
|
10
|
+
|
|
11
|
+
## Use This Architecture
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
opencode Conductor (opencode --dangerously-skip-permissions)
|
|
15
|
+
│
|
|
16
|
+
│ Geometra MCP: navigates portals (logged-in sessions)
|
|
17
|
+
│ Reads structured page model — the user sees everything in real time
|
|
18
|
+
│
|
|
19
|
+
├─ Offer 1: reads JD from DOM + URL
|
|
20
|
+
│ └─► opencode run worker → report .md + PDF + tracker-line
|
|
21
|
+
│
|
|
22
|
+
├─ Offer 2: click next, reads JD + URL
|
|
23
|
+
│ └─► opencode run worker → report .md + PDF + tracker-line
|
|
24
|
+
│
|
|
25
|
+
└─ End: merge tracker-additions → data/applications/ + summary
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Each worker is a child `opencode run` with a clean 200K token context. The conductor only orchestrates.
|
|
29
|
+
|
|
30
|
+
## Read These Files
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
batch/
|
|
34
|
+
batch-input.tsv # URLs (from conductor or manual)
|
|
35
|
+
batch-state.tsv # Progress (auto-generated, gitignored)
|
|
36
|
+
batch-runner.sh # Standalone orchestrator script
|
|
37
|
+
batch-prompt.md # Prompt template for workers
|
|
38
|
+
logs/ # One log per offer (gitignored)
|
|
39
|
+
tracker-additions/ # Tracker lines (gitignored)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Run Mode A Conductor --chrome
|
|
43
|
+
|
|
44
|
+
1. **Read state**: `batch/batch-state.tsv` → know what has already been processed
|
|
45
|
+
2. **Navigate portal**: Chrome → search URL
|
|
46
|
+
3. **Extract URLs**: Read results DOM → extract URL list → append to `batch-input.tsv`
|
|
47
|
+
4. **For each pending URL**:
|
|
48
|
+
a. Chrome: click on the offer → read JD text from DOM
|
|
49
|
+
b. Save JD to `/tmp/batch-jd-{id}.txt`
|
|
50
|
+
c. Calculate next sequential REPORT_NUM
|
|
51
|
+
d. Execute via Bash:
|
|
52
|
+
```bash
|
|
53
|
+
opencode run --dangerously-skip-permissions \
|
|
54
|
+
--file batch/batch-prompt.md \
|
|
55
|
+
"Process this offer. URL: {url}. JD: /tmp/batch-jd-{id}.txt. Report: {num}. ID: {id}"
|
|
56
|
+
```
|
|
57
|
+
e. Update `batch-state.tsv` (completed/failed + score + report_num)
|
|
58
|
+
f. Log to `logs/{report_num}-{id}.log`
|
|
59
|
+
g. Chrome: go back → next offer
|
|
60
|
+
5. **Pagination**: If no more offers → click "Next" → repeat
|
|
61
|
+
6. **End**: Merge `tracker-additions/` → `data/applications/` (via `merge-tracker.mjs`) + summary
|
|
62
|
+
|
|
63
|
+
## Run Mode B Standalone Script
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
batch/batch-runner.sh [OPTIONS]
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Options:
|
|
70
|
+
- `--dry-run` — list pending without executing
|
|
71
|
+
- `--retry-failed` — only retry failed ones
|
|
72
|
+
- `--start-from N` — start from ID N
|
|
73
|
+
- `--parallel N` — N workers in parallel
|
|
74
|
+
- `--max-retries N` — attempts per offer (default: 2)
|
|
75
|
+
|
|
76
|
+
## Read batch-state.tsv Format
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
id url status started_at completed_at report_num score error retries
|
|
80
|
+
1 https://... completed 2026-... 2026-... 002 4.2 - 0
|
|
81
|
+
2 https://... failed 2026-... 2026-... - - Error msg 1
|
|
82
|
+
3 https://... pending - - - - - 0
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Use Resumability
|
|
86
|
+
|
|
87
|
+
- If it dies → re-run → reads `batch-state.tsv` → skips completed
|
|
88
|
+
- Lock file (`batch-runner.pid`) prevents double execution
|
|
89
|
+
- Each worker is independent: failure on offer #47 does not affect the rest
|
|
90
|
+
|
|
91
|
+
## Run Workers (opencode run)
|
|
92
|
+
|
|
93
|
+
Each worker receives `batch-prompt.md` as system prompt. It is self-contained.
|
|
94
|
+
|
|
95
|
+
The worker produces:
|
|
96
|
+
1. Report `.md` in `reports/`
|
|
97
|
+
2. PDF in `output/`
|
|
98
|
+
3. Tracker line in `batch/tracker-additions/{id}.tsv`
|
|
99
|
+
4. JSON result via stdout
|
|
100
|
+
|
|
101
|
+
## Apply Error Handling
|
|
102
|
+
|
|
103
|
+
| Error | Recovery |
|
|
104
|
+
|-------|----------|
|
|
105
|
+
| URL inaccessible | Worker fails → conductor marks `failed`, moves on |
|
|
106
|
+
| JD behind login | Conductor tries to read DOM. If it fails → `failed` |
|
|
107
|
+
| Portal changes layout | Conductor reasons about HTML, adapts |
|
|
108
|
+
| Worker crashes | Conductor marks `failed`, moves on. Retry with `--retry-failed` |
|
|
109
|
+
| Conductor dies | Re-run → reads state → skips completed |
|
|
110
|
+
| PDF fails | Report .md is saved. PDF remains pending |
|
package/modes/compare.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Mode: compare — Multi-Offer Comparison
|
|
2
|
+
|
|
3
|
+
**Uses the Canonical Scoring Model from `modes/_shared.md`** — the same 10 weighted dimensions used in `offer`, `auto-pipeline`, and `batch` evaluations. This means scores from prior evaluations are directly comparable. No need to re-score unless the user explicitly requests it.
|
|
4
|
+
|
|
5
|
+
## Run This Workflow
|
|
6
|
+
|
|
7
|
+
1. **Gather offers**: Ask the user for offers if not in context. Can be text, URLs, or references to already-evaluated offers in the tracker.
|
|
8
|
+
2. **Score each offer**: If an offer was already evaluated (has a report in `reports/`), read the existing per-dimension scores from the report. If not yet evaluated, score using the full Canonical Scoring Model.
|
|
9
|
+
3. **Build comparison matrix**: Show all 10 dimensions side-by-side across offers, with the weighted total.
|
|
10
|
+
4. **Rank and recommend**: Final ranking with recommendation. Highlight where offers differ most (the dimensions that actually discriminate). Include time-to-offer as a tiebreaker when scores are close (within 0.3).
|
|
11
|
+
|
|
12
|
+
## Output format
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
| Dimension (weight) | Offer A | Offer B | Offer C |
|
|
16
|
+
|---------------------|---------|---------|---------|
|
|
17
|
+
| North Star (25%) | X/5 | X/5 | X/5 |
|
|
18
|
+
| CV match (15%) | ... | ... | ... |
|
|
19
|
+
| ... | ... | ... | ... |
|
|
20
|
+
| **Weighted total** | **X.X** | **X.X** | **X.X** |
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Then: narrative recommendation explaining which offer to prioritize and why, considering both score and practical factors (timeline, negotiation leverage, start-date flexibility, competing offer stages).
|
package/modes/contact.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Mode: contact — LinkedIn Power Move
|
|
2
|
+
|
|
3
|
+
## Step 0 — Load evaluation context
|
|
4
|
+
|
|
5
|
+
Check for an existing evaluation report before generating any message.
|
|
6
|
+
|
|
7
|
+
1. Identify the company + role (from user input, current conversation, or most recent evaluation).
|
|
8
|
+
2. Search `reports/` for a matching report (Grep case-insensitive by company name).
|
|
9
|
+
3. Read any matching report and extract these fields (all block references below point into `modes/offer.md`).
|
|
10
|
+
<!-- isolint-disable-next-line undefined-step-reference -->
|
|
11
|
+
- **Archetype** detected (Step 0 of evaluation).
|
|
12
|
+
<!-- isolint-disable-next-line undefined-step-reference -->
|
|
13
|
+
- **Top 3 proof points** from Block B (the JD requirements where CV match was strongest).
|
|
14
|
+
<!-- isolint-disable-next-line undefined-step-reference -->
|
|
15
|
+
- **Score** and key gaps from Block B.
|
|
16
|
+
<!-- isolint-disable-next-line undefined-step-reference -->
|
|
17
|
+
- **STAR stories** from Block F that are most relevant.
|
|
18
|
+
<!-- isolint-disable-next-line undefined-step-reference -->
|
|
19
|
+
- **Case study** recommended in Block F.
|
|
20
|
+
4. Also read all day files in `data/applications/` to check current status of this application.
|
|
21
|
+
5. If NO report exists, inform the user and offer to run an evaluation first — or proceed with cv.md only.
|
|
22
|
+
|
|
23
|
+
The loaded evaluation context is what makes the outreach message specific instead of generic.
|
|
24
|
+
|
|
25
|
+
## Step 1 — Identify Targets
|
|
26
|
+
|
|
27
|
+
Use WebSearch to find:
|
|
28
|
+
|
|
29
|
+
- Hiring manager of the team.
|
|
30
|
+
- Recruiter assigned to the role.
|
|
31
|
+
- 2-3 peers on the team (people in a similar role).
|
|
32
|
+
|
|
33
|
+
## Step 2 — Select primary target
|
|
34
|
+
|
|
35
|
+
Choose the person who would most benefit from the candidate joining. Typically:
|
|
36
|
+
|
|
37
|
+
- For IC roles: the hiring manager or tech lead.
|
|
38
|
+
- For leadership roles: a peer or the person the role reports to.
|
|
39
|
+
- Avoid cold-messaging the recruiter first unless no other option — a warm intro from a team member is stronger.
|
|
40
|
+
|
|
41
|
+
## Step 3 — Generate message
|
|
42
|
+
|
|
43
|
+
Generate the message directly from the evaluation report, not generic claims.
|
|
44
|
+
|
|
45
|
+
Framework (3 sentences, max 300 characters for LinkedIn connection request):
|
|
46
|
+
|
|
47
|
+
<!-- isolint-disable-next-line undefined-step-reference -->
|
|
48
|
+
- **Sentence 1 (Hook)**: Something specific about their company or current challenge with AI — NOT generic. If the report's Block A identified the domain and function, reference it.
|
|
49
|
+
<!-- isolint-disable-next-line undefined-step-reference -->
|
|
50
|
+
- **Sentence 2 (Proof)**: The single strongest proof point from Block B's top matches. Use the exact framing that scored highest against the JD. If article-digest.md has a quantified metric for this proof point, use it.
|
|
51
|
+
- **Sentence 3 (Proposal)**: Quick chat, no pressure — "Would love to chat about [specific topic from the JD] for 15 min".
|
|
52
|
+
|
|
53
|
+
**Archetype-adapted framing** from the report — use the single row matching the detected archetype:
|
|
54
|
+
|
|
55
|
+
| Archetype | Emphasize |
|
|
56
|
+
|-----------|-----------|
|
|
57
|
+
| FDE | fast delivery, client-facing results |
|
|
58
|
+
| SA | system design, integration wins |
|
|
59
|
+
| PM | product discovery, stakeholder outcomes |
|
|
60
|
+
| LLMOps | production metrics, evals, observability |
|
|
61
|
+
| Agentic | orchestration, reliability, HITL |
|
|
62
|
+
| Transformation | adoption, change management, org impact |
|
|
63
|
+
|
|
64
|
+
## Step 4 — Generate Versions
|
|
65
|
+
|
|
66
|
+
Generate:
|
|
67
|
+
- EN (default)
|
|
68
|
+
<!-- isolint-disable-next-line undefined-step-reference -->
|
|
69
|
+
- **Follow-up variant**: A longer version (2-3 sentences) for LinkedIn InMail or email, where the 300-char limit doesn't apply. This version can include a second proof point and a link to the relevant case study from Block F.
|
|
70
|
+
|
|
71
|
+
## Step 5 — List Alternative Targets
|
|
72
|
+
|
|
73
|
+
List 2-3 backup contacts with justification for why they're strong second choices.
|
|
74
|
+
|
|
75
|
+
## Apply These Message Rules
|
|
76
|
+
|
|
77
|
+
- Max 300 characters for connection request version
|
|
78
|
+
- NO corporate-speak
|
|
79
|
+
- NO "I'm passionate about..."
|
|
80
|
+
- Something that makes them want to respond
|
|
81
|
+
- NEVER share phone number
|
|
82
|
+
- **Every claim must trace back to cv.md or article-digest.md** — no invented metrics
|
package/modes/deep.md
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Mode: deep — Deep Company Research
|
|
2
|
+
|
|
3
|
+
Structured company research that feeds directly into evaluations and interview prep.
|
|
4
|
+
|
|
5
|
+
## Step 0 — Check for existing evaluation
|
|
6
|
+
|
|
7
|
+
Check `reports/` for an existing evaluation of this company+role before researching. If found, load the report — deep research MUST build on what the evaluation already identified (archetype, gaps, proof points), not start from scratch.
|
|
8
|
+
|
|
9
|
+
## Scan These 6 Research Axes
|
|
10
|
+
|
|
11
|
+
### Scan Axis 1: AI Strategy
|
|
12
|
+
- What products/features use AI/ML?
|
|
13
|
+
- What's their AI stack? (models, infra, tools)
|
|
14
|
+
- Engineering blog — what do they publish?
|
|
15
|
+
- Papers or talks on AI?
|
|
16
|
+
|
|
17
|
+
### Scan Axis 2: Recent Moves (last 6 months)
|
|
18
|
+
- Relevant hires in AI/ML/product?
|
|
19
|
+
- Acquisitions or partnerships?
|
|
20
|
+
- Product launches or pivots?
|
|
21
|
+
- Funding rounds or leadership changes?
|
|
22
|
+
|
|
23
|
+
### Scan Axis 3: Engineering Culture
|
|
24
|
+
- How do they ship? (deploy cadence, CI/CD)
|
|
25
|
+
- Mono-repo or multi-repo?
|
|
26
|
+
- Languages/frameworks?
|
|
27
|
+
- Remote-first or office-first?
|
|
28
|
+
- Glassdoor/Blind reviews on eng culture?
|
|
29
|
+
|
|
30
|
+
### Scan Axis 4: Likely Challenges
|
|
31
|
+
- Scaling problems?
|
|
32
|
+
- Reliability, cost, latency challenges?
|
|
33
|
+
- Migrating anything? (infra, models, platforms)
|
|
34
|
+
- Pain points from reviews?
|
|
35
|
+
|
|
36
|
+
### Scan Axis 5: Competitors And Differentiation
|
|
37
|
+
- Main competitors?
|
|
38
|
+
- Moat/differentiator?
|
|
39
|
+
- Positioning vs competition?
|
|
40
|
+
|
|
41
|
+
### Scan Axis 6: Candidate Angle
|
|
42
|
+
cv.md is already in context via opencode.json:instructions — do NOT Read it again. Read profile.yml once if you need identity fields:
|
|
43
|
+
- What unique value does the candidate bring to this team?
|
|
44
|
+
- Which projects are most relevant?
|
|
45
|
+
- What story should they tell in the interview?
|
|
46
|
+
|
|
47
|
+
## Feed Research Back Into Evaluation
|
|
48
|
+
|
|
49
|
+
**The feedback loop is the key step that makes deep research actionable.**
|
|
50
|
+
|
|
51
|
+
After completing the 6 axes, update the evaluation if one exists:
|
|
52
|
+
|
|
53
|
+
1. **Score adjustments**: Deep research may reveal information that changes scoring dimensions.
|
|
54
|
+
- Company reputation (axis 3: culture) → dimension #7.
|
|
55
|
+
- Tech stack modernity (axis 1: AI strategy) → dimension #8.
|
|
56
|
+
- Speed to offer (axis 2: recent moves, hiring pace) → dimension #9.
|
|
57
|
+
- Cultural signals (axis 3: culture) → dimension #10.
|
|
58
|
+
- Growth trajectory (axis 2: funding, launches) → dimension #5.
|
|
59
|
+
|
|
60
|
+
2. **Append a `## Deep Research` section to the existing report** with findings organized by axis. Include date of research so it can be refreshed.
|
|
61
|
+
|
|
62
|
+
<!-- isolint-disable-next-line undefined-step-reference -->
|
|
63
|
+
3. **Update Block F (Interview Plan)**: The "likely challenges" (axis 4) directly inform STAR story selection — pick stories that address the company's actual problems, not generic ones.
|
|
64
|
+
|
|
65
|
+
4. **Update contact targeting**: The "recent moves" (axis 2) often reveal who to reach out to (new hires, team leads mentioned in blog posts).
|
|
66
|
+
|
|
67
|
+
<!-- isolint-disable-next-line undefined-step-reference -->
|
|
68
|
+
If NO evaluation exists yet, save the research to `reports/deep-{company-slug}-{date}.md` so it's available when the user evaluates later. The evaluation mode MUST check for existing deep research before starting Block D (Comp & Demand).
|
|
69
|
+
|
|
70
|
+
## Output Format
|
|
71
|
+
|
|
72
|
+
```markdown
|
|
73
|
+
## Deep Research: [Company] — [Role]
|
|
74
|
+
**Date:** YYYY-MM-DD
|
|
75
|
+
**Linked report:** #NNN (if exists)
|
|
76
|
+
|
|
77
|
+
### 1. AI Strategy
|
|
78
|
+
(findings)
|
|
79
|
+
|
|
80
|
+
### 2. Recent Moves
|
|
81
|
+
(findings)
|
|
82
|
+
|
|
83
|
+
### 3. Engineering Culture
|
|
84
|
+
(findings)
|
|
85
|
+
|
|
86
|
+
### 4. Likely Challenges
|
|
87
|
+
(findings)
|
|
88
|
+
|
|
89
|
+
### 5. Competitors & Differentiation
|
|
90
|
+
(findings)
|
|
91
|
+
|
|
92
|
+
### 6. Candidate Angle
|
|
93
|
+
(findings)
|
|
94
|
+
|
|
95
|
+
### Score Impact
|
|
96
|
+
| Dimension | Before | After | Why |
|
|
97
|
+
|-----------|--------|-------|-----|
|
|
98
|
+
(only dimensions where research changed the score)
|
|
99
|
+
```
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Mode: followup — Follow-Up Timing & Nudge System
|
|
2
|
+
|
|
3
|
+
Scans all day files in `data/applications/` for entries that need follow-up action based on their current state and how long they've been in that state.
|
|
4
|
+
|
|
5
|
+
**This mode is read-only on existing pipeline logic.** It reads the tracker and suggests actions — it never changes scores, reports, or pipeline behavior.
|
|
6
|
+
|
|
7
|
+
## Timing Rules
|
|
8
|
+
|
|
9
|
+
| Current State | Days Since | Action |
|
|
10
|
+
|---------------|-----------|--------|
|
|
11
|
+
| Applied | 7-10 days | Nudge: LinkedIn outreach via `/job-forge contact` if not already Contacted |
|
|
12
|
+
| Applied | 14+ days | Flag as stale. Suggest: nudge or archive to Discarded |
|
|
13
|
+
| Contacted | 5-7 days | Follow-up message (shorter, reference first message) |
|
|
14
|
+
| Contacted | 14+ days | Flag as stale. Likely no response — move on |
|
|
15
|
+
| Responded | 5 days | If no next step scheduled, ask: "Did they propose a call?" |
|
|
16
|
+
| Interview | 1 day after | Send thank-you note (generate draft) |
|
|
17
|
+
| Interview | 7+ days no update | Nudge recruiter: "Following up on our conversation last week" |
|
|
18
|
+
| Evaluated | 14+ days | Stale evaluation. Offer may be closed — suggest verifying or archiving |
|
|
19
|
+
|
|
20
|
+
## Run This Workflow
|
|
21
|
+
|
|
22
|
+
1. **Read** all day files in `data/applications/` — parse all entries with dates.
|
|
23
|
+
2. **Compute** days since the date column for each entry (using today's date).
|
|
24
|
+
3. **Filter** to entries matching the Timing Rules table above.
|
|
25
|
+
4. **Sort** by urgency (most overdue first).
|
|
26
|
+
5. **Present** action list.
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
## Follow-Up Actions — {today's date}
|
|
30
|
+
|
|
31
|
+
### Urgent (overdue)
|
|
32
|
+
- #045 Anthropic — AI Engineer | Applied 12 days ago → Nudge via LinkedIn
|
|
33
|
+
- #078 Datadog — Staff PM | Interviewed 8 days ago → Follow up with recruiter
|
|
34
|
+
|
|
35
|
+
### Coming Up (next 3 days)
|
|
36
|
+
- #102 Stripe — AI Platform | Applied 6 days ago → Nudge window opens in 1 day
|
|
37
|
+
|
|
38
|
+
### Stale (consider archiving)
|
|
39
|
+
- #023 OldCo — Senior Eng | Evaluated 21 days ago → Verify if still open or Discard
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Nudge Message Generation
|
|
43
|
+
|
|
44
|
+
When the user selects an entry to nudge:
|
|
45
|
+
|
|
46
|
+
1. Read the existing report from `reports/`.
|
|
47
|
+
2. Use the **contact** mode logic to generate a follow-up message (not a first outreach).
|
|
48
|
+
3. Follow-up messages are shorter and reference the application.
|
|
49
|
+
- "I applied to [role] [N days] ago and wanted to follow up...".
|
|
50
|
+
<!-- isolint-disable-next-line undefined-step-reference -->
|
|
51
|
+
- Reference one specific proof point from Block B (see `modes/offer.md`).
|
|
52
|
+
- Keep it under 200 characters for LinkedIn.
|
|
53
|
+
|
|
54
|
+
## Generate Thank-You Notes
|
|
55
|
+
|
|
56
|
+
After interviews, generate a thank-you note.
|
|
57
|
+
<!-- isolint-disable-next-line undefined-step-reference -->
|
|
58
|
+
1. Read the report + Block F STAR stories (Block F lives in `modes/offer.md`).
|
|
59
|
+
2. Reference something specific discussed in the interview (ask the user what stood out).
|
|
60
|
+
3. Reinforce one proof point.
|
|
61
|
+
4. 3-4 sentences max, send within 24 hours.
|
|
62
|
+
|
|
63
|
+
## Automate This Mode
|
|
64
|
+
|
|
65
|
+
The followup mode works well with `/loop` or `/schedule`:
|
|
66
|
+
|
|
67
|
+
- Run `/job-forge followup` every 2-3 days to catch nudge windows.
|
|
68
|
+
- Suggest this to the user after their first batch of applications.
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# Mode: negotiation — Offer Negotiation
|
|
2
|
+
|
|
3
|
+
Structured mode for when the user receives an actual job offer. Completely separate from `offer` (which evaluates job postings).
|
|
4
|
+
|
|
5
|
+
**This mode is standalone.** It reads existing data (reports, tracker, profile.yml) but creates its own output. No changes to existing pipeline behavior.
|
|
6
|
+
|
|
7
|
+
## Use These Trigger Conditions
|
|
8
|
+
|
|
9
|
+
- User says "I got an offer from [company]".
|
|
10
|
+
- User updates a tracker entry to Offer.
|
|
11
|
+
- User runs `/job-forge negotiation`.
|
|
12
|
+
|
|
13
|
+
## Step 1 — Capture The Offer
|
|
14
|
+
|
|
15
|
+
Ask the user for the offer details (or read from a document/screenshot):
|
|
16
|
+
|
|
17
|
+
| Field | Example | Notes |
|
|
18
|
+
|-------|---------|-------|
|
|
19
|
+
| Base salary | $180,000 | Annual |
|
|
20
|
+
| Equity/RSUs | $50,000/yr (4yr vest) | Total grant ÷ vesting period |
|
|
21
|
+
| Signing bonus | $20,000 | One-time |
|
|
22
|
+
| Annual bonus | 15% target | As % of base |
|
|
23
|
+
| Benefits | Standard | Healthcare, 401k match, dental, vision |
|
|
24
|
+
| PTO | Unlimited / 20 days | |
|
|
25
|
+
| Remote policy | Full remote | |
|
|
26
|
+
| Start date | YYYY-MM-DD | |
|
|
27
|
+
| Deadline to respond | YYYY-MM-DD | Critical — drives urgency |
|
|
28
|
+
| Level/title | Senior Engineer | |
|
|
29
|
+
| Other perks | $5K learning budget | Anything else |
|
|
30
|
+
|
|
31
|
+
## Step 2 — Total Comp Calculation
|
|
32
|
+
|
|
33
|
+
Compute total annual comp:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
Base: $180,000
|
|
37
|
+
Equity (annual): $50,000 (total grant ÷ vesting years)
|
|
38
|
+
Bonus (target): $27,000 (base × bonus %)
|
|
39
|
+
Signing (annual): $10,000 (signing ÷ 2, amortized over first 2 years)
|
|
40
|
+
───────────────────────────
|
|
41
|
+
Total Year 1: $267,000
|
|
42
|
+
Total Ongoing: $257,000 (without signing bonus amortization)
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
**For equity at private companies:**
|
|
46
|
+
- Apply a discount: pre-IPO equity is illiquid. Common: 50-70% discount for early stage, 20-30% for late stage.
|
|
47
|
+
- Note the strike price if options (not RSUs). Compute current spread if possible.
|
|
48
|
+
- Flag if there's no secondary market.
|
|
49
|
+
|
|
50
|
+
## Step 3 — Compare Against Target & Pipeline
|
|
51
|
+
|
|
52
|
+
Read from `config/profile.yml`:
|
|
53
|
+
- `compensation.target_range` — is the offer within, above, or below?
|
|
54
|
+
- `compensation.minimum` — is it above the walk-away number?
|
|
55
|
+
|
|
56
|
+
Read from all day files in `data/applications/`:
|
|
57
|
+
- Count other offers at Interview or Offer stage (these in-flight offers form your leverage).
|
|
58
|
+
- What scores did those have? (Higher-scored alternatives = stronger negotiating position.)
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
## Leverage Assessment
|
|
62
|
+
|
|
63
|
+
Active pipeline:
|
|
64
|
+
- Offer: [this one] + N others
|
|
65
|
+
- Interview stage: N companies
|
|
66
|
+
- Applied (awaiting): N companies
|
|
67
|
+
|
|
68
|
+
Leverage: [Strong/Moderate/Weak]
|
|
69
|
+
- Strong: 2+ competing offers or 3+ active interviews
|
|
70
|
+
- Moderate: 1 other offer or 2+ interviews
|
|
71
|
+
- Weak: this is the only active opportunity
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Step 4 — Build Counter-Offer Strategy
|
|
75
|
+
|
|
76
|
+
Build the strategy based on leverage and gap to target.
|
|
77
|
+
|
|
78
|
+
**If offer is below target range:**
|
|
79
|
+
```
|
|
80
|
+
Recommended counter: [target midpoint + 10%]
|
|
81
|
+
Justification: "Based on market data for [role] at [level],
|
|
82
|
+
and given [competing offers / pipeline activity], I'm targeting [range]."
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**If offer is within target range:**
|
|
86
|
+
```
|
|
87
|
+
Recommended counter: [target top end]
|
|
88
|
+
Justification: "I'm excited about this role. To make the decision
|
|
89
|
+
straightforward, [specific ask — e.g., bump equity, signing bonus, level]."
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
**If offer is above target range:**
|
|
93
|
+
```
|
|
94
|
+
Focus negotiation on non-comp factors: level/title, scope,
|
|
95
|
+
team choice, start date flexibility, remote policy.
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Generate Negotiation Scripts (adapted from _shared.md)
|
|
99
|
+
|
|
100
|
+
Generate 3 scripts ready for use:
|
|
101
|
+
|
|
102
|
+
1. **Initial response** (buy time): "Thank you for the offer. I'm very interested and want to give this proper consideration. Can I have until [deadline or +3 days] to review the full package?"
|
|
103
|
+
|
|
104
|
+
<!-- isolint-disable-next-line undefined-step-reference -->
|
|
105
|
+
2. **Counter-offer** when comp is below the target range: Specific to the gap. Reference market data from Block D (see `modes/offer.md`) when available. Never give a single number — always a range.
|
|
106
|
+
|
|
107
|
+
3. **Acceptance** (when ready): Confirm all terms in writing. Ask for the offer letter with the agreed terms before giving verbal acceptance.
|
|
108
|
+
|
|
109
|
+
### Skip These Negotiation Anti-Patterns
|
|
110
|
+
- Never counter before understanding the full package
|
|
111
|
+
- Never reveal your current comp or other offer amounts
|
|
112
|
+
- Never give an ultimatum unless you're prepared to walk
|
|
113
|
+
- Never negotiate via email if you can do it via call (nuance matters)
|
|
114
|
+
|
|
115
|
+
## Step 5 — Build Decision Framework
|
|
116
|
+
|
|
117
|
+
Build a decision matrix when the user has multiple offers, using the same scoring dimensions from `_shared.md`.
|
|
118
|
+
|
|
119
|
+
```
|
|
120
|
+
| Dimension | Offer A | Offer B |
|
|
121
|
+
|-----------|---------|---------|
|
|
122
|
+
| Total comp (Year 1) | $267K | $245K |
|
|
123
|
+
| Equity upside | Moderate (Series C) | High (Series A) |
|
|
124
|
+
| Role match (from eval) | 4.5/5 | 3.8/5 |
|
|
125
|
+
| Growth trajectory | Clear path to Staff | Flat org |
|
|
126
|
+
| Remote quality | Full remote | Hybrid 2x/week |
|
|
127
|
+
| Gut feeling | High | Medium |
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Include a "gut feeling" row — quantitative analysis doesn't capture everything.
|
|
131
|
+
|
|
132
|
+
## Step 6 — Save And Update Tracker
|
|
133
|
+
|
|
134
|
+
Update the tracker entry to reflect the offer.
|
|
135
|
+
|
|
136
|
+
1. Update the entry in its day file under `data/applications/YYYY-MM-DD.md`: status → `Offer`, notes → comp summary.
|
|
137
|
+
2. Append `## Offer Details` section to the existing report with full comp breakdown and negotiation outcome.
|
|
138
|
+
3. If the user accepts: status → a new note like `Accepted YYYY-MM-DD`.
|
|
139
|
+
|
|
140
|
+
## Manage The Deadline
|
|
141
|
+
|
|
142
|
+
When the user has a response deadline, run these checks in order.
|
|
143
|
+
|
|
144
|
+
1. Calculate business days remaining.
|
|
145
|
+
2. If < 3 business days remain AND other interviews are active, suggest: "Ask [company] for an extension — 'I want to make a thoughtful decision and have a final interview scheduled this week. Could we extend to [date]?'"
|
|
146
|
+
3. If the deadline is firm and leverage is weak, help the user decide with what they have.
|