feat: import candidate brief from LinkedIn profile (#48)#52
Merged
Conversation
Adds an optional LinkedIn-import path alongside CV upload for generating config/candidate-brief.md, using LinkedIn's self-serve "Save to PDF" export (no scraping/auth, ToS-safe) through the existing parse → LLM pipeline with a LinkedIn-tuned prompt. - src/lib/brief-prompt.ts: single shared buildBriefPrompt(text, source, maxChars) with a 'cv' | 'linkedin' source. Consolidates the prompt that was duplicated in setup-brief.ts and ui/plugins/brief.ts; the output contract (3 paragraphs) is identical across sources so quality matches. - ui/plugins/brief.ts + _shared.ts: /api/cv accepts an optional, allowlist- validated `source`; defaults to 'cv'. - ui/src/lib/api/index.ts: cv.upload input gains optional `source`. - ui/src/Onboarding.tsx: optional "Import from LinkedIn" affordance in the CV-upload step (collapsed; reveals Save-to-PDF steps + PDF picker). - ui/src/Profile.tsx: matching "From LinkedIn" toggle on the Profile tab. - src/setup-brief.ts: `--linkedin <file>` flag + filename auto-detect. - Tests (brief-prompt.test.ts, Onboarding.test.tsx) + README docs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Profile.tsx: wrap summarizeFile in try/finally so a throw in fileToBase64/fileToText can't leave `busy` stuck and disable the tab (HIGH). Make the "Paste text" / "From LinkedIn" panels mutually exclusive — opening one closes the other (MEDIUM). - setup-brief.ts: match the LinkedIn filename auto-detect on basename only, so a "linkedin"-named directory can't silently flip a real CV to the LinkedIn prompt (MEDIUM). - Onboarding.test.tsx: add an integration test asserting source=linkedin actually reaches POST /api/cv (regression guard for the upload wiring) (MEDIUM). - brief-prompt.test.ts: tighten the CV "no-leak" assertion to check the exact LinkedIn copy instead of a broad /LinkedIn/i glob (LOW). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
FranRom
approved these changes
May 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #48.
Adds an optional "Import from LinkedIn" path for generating
config/candidate-brief.md, alongside the existing CV upload. Uses LinkedIn's self-serve "Save to PDF" export (no scraping, no auth, ToS-safe) fed through the existing parse → LLM pipeline with a LinkedIn-tuned prompt — the issue's recommended first cut.What's in it
src/lib/brief-prompt.ts(new) — single sharedbuildBriefPrompt(text, source, maxChars)with a'cv' | 'linkedin'source. Consolidates the prompt that was duplicated insetup-brief.tsandui/plugins/brief.ts; the 3-paragraph output contract is identical across sources so a LinkedIn-sourced brief is comparable to a CV-sourced one.ui/plugins/brief.ts+_shared.ts—POST /api/cvaccepts an optional, allowlist-validatedsource(defaults tocv).ui/src/lib/api/index.ts—cv.uploadinput gains optionalsource.ui/src/Onboarding.tsx— optional "Import from LinkedIn" affordance in the CV-upload step (collapsed; expands to the Save-to-PDF steps + a PDF picker).ui/src/Profile.tsx— matching "From LinkedIn" toggle on the Profile tab.src/setup-brief.ts—--linkedin <file>flag + basename-scoped filename auto-detect.setup-briefCLI block, and the Profile-tab description.Commits
feat:the LinkedIn import implementationfix:code-review findings (busy-statetry/finally, mutually-exclusive Profile panels, basename-only auto-detect, an integration test assertingsource=linkedinreaches/api/cv, tightened CV no-leak assertion)Security
Local-only dev-server middleware. The
sourcefield is allowlist-validated before any LLM call; no new path/SSRF/injection surface; document-in-prompt posture unchanged from the existing CV path (self-owned input, local-only).Test plan
pnpm run lint,pnpm run typecheck,pnpm run lint:ui-patterns— greenpnpm test— 420 pass (newtests/brief-prompt.test.ts+Onboarding.test.tsxLinkedIn cases)pnpm run build+pnpm run ui:build— green; bundle within budget (LinkedIn UI lives in lazy chunks)pnpm run setup-brief --linkedin ~/profile.pdf🤖 Generated with Claude Code