Spec #15 — Negotiation Coaching
Status: Done (shipped 2026-06-15) · Owner: Hust · Effort: M · Phase 3 · Depends on: #3 + comp data (#1)
1. Problem & user value
The offer stage is high-value and high-stress, and most tools ignore it. Hust can coach: market- anchored target ranges, cited scripts for counter-offers, and what to ask for beyond base.
2. Scope
In: offer-stage guidance — target range from Ever Jobs comp/market data (#1)
- the user's level; cited negotiation scripts (counter, competing-offer, non-comp asks); a checklist. Out: doing the negotiation for the user; legal advice.
3. Design
- A
negotiationCoachtool: inputs the offer + role + user level; outputs a target range (with the market basis cited), scripts, and a structured artifact (#5). - Market anchoring from #1's
/analyzedata + the #3 Comp/Demand block. Honest about uncertainty. - HITL: drafts scripts; the user sends nothing through Hust.
4. Plan & tasks
negotiationCoachtool (Zod, structured artifact); market-range computation (cited).- Scripts library (counter / competing / non-comp), grounded + no-invent.
- UI: offer-stage panel on the application detail (Kanban
offerstage). - Tests: range math from fixture market data; structured artifact; no invented figures.
5. Acceptance
- At the
offerstage a user gets a cited target range + scripts; figures trace to market data; CI green; zero competitor references.
Implementation (shipped)
- AI tool —
negotiationBriefToolinpackages/ai/src/tools/negotiation-brief.ts, exported viapackages/ai/src/tools/index.ts. Registered with the orchestrator as thenegotiationBrieftool (packages/ai/src/agents/orchestrator.ts), withuserId+modelinjected server-side. - Structured schema (#5) —
packages/ai/src/structured/schemas/negotiation.tsdefinesnegotiationDraftSchema/negotiationSummarySchemaand thenegotiationArtifact(defineArtifact("negotiation", v1)); re-exported frompackages/ai/src/structured/index.ts. - Output shape — market-anchored
targetRange(low/high + citedbasis), 3–5 leverage points, 2–3 scripts (counter/competing_offer/non_comp_ask), and pitfalls. - Grounding / no-invent (#6) — figures are derived only from grounded salary facts (job posting
salaryMin/salaryMax/salaryInterval+ the user'spreferences.salaryMin/Max+ optionalcurrentOffer); the prose is audited viaassertNoInvented(packages/ai/src/policy/assert-no-invented.ts), settinggrounded+flaggedClaims. No invented compensation numbers. - Data source — reads the
jobsanduserstables via Drizzle (@ever-hust/db); no new table was added (the artifact is produced on demand, not persisted to its own table). - UI surface — the negotiation artifact renders on the jobs canvas through the generic,
shape-agnostic structured-artifact card
apps/web/components/canvas/artifact-card.tsx(wired viaapps/web/hooks/use-canvas-sync.ts); also exportable to PDF viaapps/web/lib/pdf/artifact-document.tsx. - Tests —
packages/ai/src/tools/negotiation-brief.test.tsandpackages/ai/src/structured/schemas/negotiation.test.ts(schema/range/no-invent coverage). - Deferred / not yet wired: the negotiation tool anchors on the posting salary + the user's
target directly; it does not yet consume the #3 Comp/Demand block or the #19b localized comp packs
(
packages/ai/src/comp/packs.ts) for market-semantics anchoring. A dedicated offer-stage panel on the Kanbanofferstage (plan task 3) was not built — the brief surfaces through the shared canvas artifact card instead.