_private/qwestly-docs/Features/plan/linkedin-and-resume-grader-tech-design.md

LinkedIn & Resume Grader — Tech Design Doc

Status: Most open questions resolved (Adam meetings, 2026-06-09)
Parent doc: _docs/unauthenticated-agent-onboarding-tech-design.md (pre-auth flow)
Asana: "Integrate drafts & documents into qwestly-agent" (document persistence)


1. Feature Summary

A loop-based grading and editing tool for senior tech resumes and LinkedIn profiles (engineering, product, design).

Flow: Upload → Grade (out of 10, 3 criteria) → Targeted questions → Rewrite flagged elements → Re-grade → Repeat.

Prompts: 5 total — 2 analyzers (resume, LinkedIn), 2 editors (resume, LinkedIn page), 1 dedicated about-section writer.

Stage 2 (scoped, not specified): LinkedIn post generator + post grader.


2. Decisions — Resolved

2.1 UI/UX — Where does this live? ✅

Decision: In the qwestly-agent chat, both pre-auth and post-auth.

Context Location Scope
Pre-auth (no account) questly.com/agent (public-site) Grade only — LinkedIn analyzer, score + suggestions
Post-auth (claimed account) Authenticated agent chat (candidate app) Full loop — grade, about writer, experience editor, re-grade

The grade output is shown inline in the conversation as markdown. Grade history and document management live on the dashboard (the "drafts & documents" infrastructure).

No standalone page, no separate editor UI. Everything is chat-driven with inline widgets for file uploads.

2.2 What is "the document"? ✅

Decision: Approach B — thin persistence (hybrid).

  • Grader output (grade + analysis + suggestions) is saved as a draft via the "Integrate drafts & documents" infrastructure
  • In pre-auth: grade is saved to the provisioned account's session, visible on the dashboard after claim (as a grayed-out section with a "continue" prompt)
  • In post-auth: grade + generated improvements become persisted documents with version history (profile_documents + document_grades collections)
  • The "document" is NOT directly user-editable (no Google Doc UI). Users provide context via chat and the AI does the rewriting. The "watches their document improve" experience is the grade number going up across passes shown in the conversation.

2.3 How does LinkedIn profile data get into the system? ✅

Decision: LinkedIn API (existing ingest_linkedin_profile tool).

  • User provides their LinkedIn username → agent calls ingest_linkedin_profile → structured profile data returned
  • Resume upload via in-chat HITL widget (request_file_upload tool) with the plus-button pattern already implemented in the candidate app
  • PDF parsing is handled by the existing upload pipeline (api-python doc loader)
  • No PDF-based LinkedIn extraction needed — the API path is sufficient

2.4 What happens when there's no Qwestly interview data? ✅

Decision: Degraded mode — works without interview data.

  • Pre-auth grader operates WITHOUT interview data (none exists yet)
  • It flags gaps, asks targeted questions to fill them, and uses what the user provides in-chat as the "ground truth" for that session
  • Post-auth, interview data may be available for cross-referencing claims
  • The first score becomes the baseline; subsequent improvements drive the grade up
  • Cross-referencing with interview data is a future enhancement, not a v1 gate

2.5 Can a user have multiple resumes? Multiple LinkedIn profiles? 🔓

Not addressed in the 2026-06-09 meetings. Left open for now.

Current assumption: One LinkedIn profile per user (source of truth). Possibly multiple resumes (tailored per role type), but v1 starts with one of each.

2.6 Session boundaries — is this a continuous loop or resumable? ✅

Decision: Continuous loop within a single agent session, resumable across sessions.

  • Pre-auth: session tied to httpOnly cookie (7-day expiry). User can close the browser and return to the same session.
  • Post-auth: conversations are user-scoped and persisted. User can resume any prior session from the sidebar.
  • The grade loop (grade → improve → re-grade) is continuous within a session. Improvements build on prior state — the agent knows what was graded and what was changed.

3. Data Modeling — Resolved

3.1 Approach: Thin persistence (hybrid) ✅

The "Integrate drafts & documents" Asana ticket is implementing this. Collections:

// Collection: profile_documents (via drafts infrastructure)
{
  _id: ObjectId,
  userId: string,
  type: "resume" | "linkedin_profile",
  currentContent: string,        // markdown
  currentGrade: {
    careerNarrative: number,     // 0-10
    experience: number,          // 0-10
    readability: number,         // 0-10
    composite: number,           // 0-10, equal-weighted average
  },
  currentAnalysis: object,       // full analyzer output from last pass
  createdAt: Date,
  updatedAt: Date,
}

// Collection: document_grades (version history)
{
  _id: ObjectId,
  documentId: ObjectId,
  versionNumber: number,
  content: string,
  grade: { /* same shape */ },
  analysis: object,
  sessionId: string,
  createdAt: Date,
}

Enables:

  • Grade-over-time (query document_grades sorted by createdAt)
  • "My Documents" view on the dashboard
  • Resuming work (conversation already knows the document state)

4. Grading Rubric — Resolved

4.1 Non-determinism accepted ✅

Decision (Adam, 19:03): Non-determinism is fine. The first score for a profile becomes the baseline. Subsequent runs drive the grade up from that baseline. Two cold-start runs on the same profile WILL produce different scores — that's acceptable.

Acceptance criteria: Scores should fall within ±1 point of each other for the same profile (e.g., a profile that's a 7 should never score a 5 or a 9). If scores vary by more than 1 point, the rubric needs tightening.

4.2 Rubric approach

  • Use the 3-criteria approach from the production prompts (career narrative, experience communication, readability) — NOT the 13-dimension rubric from other-notes.md
  • Hand-grading 12-20 real profiles is recommended but not required before v1 implementation — ship first with the existing prompts, tune later based on real usage
  • The build note's advice stands: track each person's grade across passes. The product is the grade going up, not the absolute number.

5. Architecture & Integration — Resolved

5.1 Where do the prompts live? ✅

Decision: Inline in qwestly-agent tool files. (Confirmed in parent tech design doc.)

Prompts 1-5 live as system instructions inside their respective agent tools: grade_linkedin_profile, generate_linkedin_about, generate_linkedin_experience, grade_resume, edit_resume. Migrate to api-python prompt infrastructure later.

5.2 How does the agent invoke the right prompt? ✅

Decision: Agent tools pattern. Each prompt is a tool registered on the orchestrator. The orchestrator decides which to call based on conversation state.

  • Pre-auth agent: Only grade_linkedin_profile is registered. No generation tools.
  • Post-auth agent: All grader + editor tools registered. The orchestrator routes based on context (user says "improve my about" → call generate_linkedin_about).

5.3 LinkedIn profile extraction ✅

Decision: LinkedIn API via ingest_linkedin_profile. Already integrated. No PDF-based LinkedIn extraction needed. Resume upload is the alternative input path (PDF → api-python doc loader → LLM structures the text).

5.4 Activity data ✅

Decision: Optional. The LinkedIn analyzer has an "uncounted activity note" that works without activity data. If unavailable, the analyzer skips it gracefully.


6. Prompt 5 Integration — About Writer ✅

6.1 Confirmed: purpose-built and working

The about writer (Prompt 5) was built for this feature. It was successfully tested in the 19:03 meeting — Adam's LinkedIn about section was generated from his profile data alone (no interview context) and produced a reasonable draft.

6.2 Integration model

  • The LinkedIn analyzer outputs an "about callout" with specific fixes
  • The about writer takes the profile JSON + additional_instructions (the about callout's fixes)
  • The transformation from analyzer output → writer input happens inside the generate_linkedin_about tool
  • Post-auth only. The about writer is NOT available in pre-auth mode.

6.3 Parallel execution

Prompts 4 (page editor) and 5 (about writer) can run in parallel within the post-auth agent — they own different sections and don't conflict. Both depend on the analyzer's output (recommendations + about callout), so they fire after the grader, not before.


7. Stage 2 — LinkedIn Post Generator/Grader

Still scoped out. The post generator needs interview data ("one recent real project from the interview") and adds prompt complexity without new data models. Ignore for v1.


8. Resolved: Pre-Auth vs Post-Auth Scope

The unauthenticated agent does LinkedIn grading only. All generation (about writer, experience editor, resume editor, re-grade loop) happens post-auth after the user claims their account.

Tool Pre-Auth Post-Auth
ingest_linkedin_profile
grade_linkedin_profile
generate_linkedin_about
generate_linkedin_experience
grade_resume ✅ (if uploaded)
edit_resume
request_file_upload
capture_email ❌ (already claimed)

See the parent tech design doc for the full pre-auth flow and system prompt.


9. Remaining Open Questions

  1. Multiple documents per user (2.5) — can a user have multiple resumes? Multiple LinkedIn profiles? v1 assumes one of each.
  2. Hand-grading calibration — the build note recommends hand-grading 12-20 real profiles before encoding a counting rubric. This hasn't been done. Ship with the qualitative rubric first, tune after real usage.
  3. Resume grader (Prompt 1) + editor (Prompt 3) — not yet implemented as agent tools. LinkedIn side is prioritized (pre-auth flow depends on it). Resume tools follow once LinkedIn is stable.
  4. Grading rubric evolution — if ±1 point variance can't be achieved with the 3-criteria qualitative rubric, fall back to the 13-dimension approach in other-notes.md for more precise scoring.

10. Next Steps

  1. Implement grade_linkedin_profile tool (LinkedIn analyzer, Prompt 2)
  2. Implement generate_linkedin_about tool (about writer, Prompt 5) — post-auth only
  3. Implement generate_linkedin_experience tool (page editor, Prompt 4) — post-auth only
  4. Wire pre-auth agent with grade-only tool set
  5. Wire post-auth agent with full grader + editor tool set
  6. Integrate with "drafts & documents" infrastructure for persistence
  7. Ship, collect real profile data, tune rubric
  8. Implement resume grader + editor (Prompts 1 + 3) once LinkedIn side is stable