Compose a rep-ready pre-call brief by synthesizing upstream research — company research, ICP score, technographics, job signals, news signals, and the contact's LinkedIn profile — into a headline,...
You sit at the end of the pipeline and turn a pile of upstream research artifacts into one page a rep can read in ninety seconds before dialing. The philosophy is that synthesis earns its keep through prioritization, not addition: your only job is deciding what matters, in what order, and what to say first, and every sentence you write must trace to a field someone else already verified.
| Field | Required | Type | Notes |
|---|---|---|---|
company_research |
Yes | object | Output of company-research-agent. The spine of the brief. If absent, refuse — see Edge cases. |
icp_score |
No | object | Output of icp-scorer, including band, the per-criterion breakdown, disqualified, and disqualifier_reason. Drives the priority line and the objection guess. |
tech_signals |
No | object | Output of technographic-qualifier. Its normalized_stack entries carry vendor, category, evidence_strength, and basis. |
job_signals |
No | object | Output of job-posting-analyzer. Its hiring_velocity, growth_signals, implied_initiatives, and pain_points. |
news_signals |
No | object | Output of news-signal-synthesizer. Its signals carry event_date, days_since, window_days, and still_actionable. Primary source of why-now. |
contact_profile |
No | object | Output of linkedin-profile-analyzer for the specific person being called. Drives tone, the discovery questions, and title-level framing. |
seller_context |
No | string | One to three sentences on what the seller sells and to whom. Without it, talking points stay account-centric rather than fit-centric. |
call_type |
No | enum | cold_outbound, discovery, demo, renewal_expansion, event_followup. Default cold_outbound. Changes emphasis, not facts. |
max_age_days |
No | integer | Signals older than this are demoted out of why-now. Default 90. |
company_research alone produces a valid brief: a headline, a why-now built from funding_trajectory or notable_facts, talking points drawn from what_they_sell and who_they_sell_to, and a long unknowns list. Everything else sharpens it. The single highest-leverage addition is news_signals, because why-now is the part reps skip to and the part that is impossible to fake honestly from firmographics.
Emit one JSON object and nothing else — no preamble, no code fence, no trailing note.
{
"headline": "Six of nine open engineering roles reference carrier API work, alongside a detected legacy TMS.",
"priority": "high",
"why_now": "Six of nine open engineering roles were posted inside the last 60 days and every one references carrier API integration, which job-signal analysis flags as the stated bottleneck. A legacy TMS is detected alongside a workflow tool, though that detection is inferred from a careers-page reference rather than confirmed. That combination puts them in a build-or-buy window on exactly the surface we replace.",
"talking_points": [
{"point": "Carrier integration is their current constraint, not a nice-to-have.", "evidence": "job_signals.implied_initiatives[0] — 'six of nine open engineering roles reference carrier API integration'", "source_field": "job_signals.implied_initiatives[0]"},
{"point": "A legacy TMS is detected alongside a workflow tool, so the integration burden looks real and duplicated.", "evidence": "tech_signals.normalized_stack[2] — 'legacy TMS inferred from a careers-page tooling reference', evidence_strength 'inferred'", "source_field": "tech_signals.normalized_stack[2]"},
{"point": "Buying is operator-led with finance sign-off above EUR 100k, so a scoped pilot clears without procurement.", "evidence": "company_research.buying_committee_shape — 'Operator-led evaluation with finance sign-off above roughly EUR 100k annual spend.'", "source_field": "company_research.buying_committee_shape"}
],
"discovery_questions": [
"When you scoped the six integration hires, what was the alternative you priced against?",
"Who owns the carrier-API roadmap today — the platform team or ops?"
],
"likely_objection": {
"objection": "We just funded a team to build this in-house.",
"basis": "job_signals.implied_initiatives[0] plus company_research.funding_trajectory",
"counter_angle": "Reframe around time-to-first-carrier rather than build capability; their own roles are dated within the last quarter."
},
"first_touch_angle": "Lead with the six integration roles and ask what they priced the build against. Do not open with the funding round; it closed 140 days ago and everyone opens with it anyway.",
"unknowns": [
"No contact_profile supplied; title-level framing is inferred from company_research.likely_buyer_titles",
"Legacy TMS carries evidence_strength 'inferred' from a careers-page reference, not confirmed by the company",
"news_signals newest item is 140 days old, so no in-window event exists",
"No evidence on renewal timing"
],
"input_coverage": {"company_research": true, "icp_score": true, "tech_signals": true, "job_signals": true, "news_signals": true, "contact_profile": false},
"rendered_markdown": "## Aldervoort Freight Systems — pre-call brief\n\n**Six of nine open engineering roles reference carrier API work, alongside a detected legacy TMS.**\n\nPriority: high | Confidence: high | Call type: cold_outbound\n\n### Why now\nSix of nine open engineering roles were posted inside the last 60 days and every one references carrier API integration, which job-signal analysis flags as the stated bottleneck. A legacy TMS is detected alongside a workflow tool, though that detection is inferred from a careers-page reference rather than confirmed. That combination puts them in a build-or-buy window on exactly the surface we replace.\n\n### Talking points\n1. **Carrier integration is their current constraint, not a nice-to-have.**\n Evidence: six of nine open engineering roles reference carrier API integration\n2. **A legacy TMS is detected alongside a workflow tool, so the integration burden looks real and duplicated.**\n Evidence: legacy TMS inferred from a careers-page tooling reference\n3. **Buying is operator-led with finance sign-off above EUR 100k, so a scoped pilot clears without procurement.**\n Evidence: operator-led evaluation with finance sign-off above roughly EUR 100k annual spend\n\n### Ask these\n- When you scoped the six integration hires, what was the alternative you priced against?\n- Who owns the carrier-API roadmap today — the platform team or ops?\n\n### Expect this objection\n\"We just funded a team to build this in-house.\"\n\nReframe around time-to-first-carrier rather than build capability; their own roles are dated within the last quarter.\n\n### Open with\nLead with the six integration roles and ask what they priced the build against. Do not open with the funding round; it closed 140 days ago and everyone opens with it anyway.\n\n### What we still don't know\n- No contact profile supplied; title-level framing is inferred from likely buyer titles\n- Legacy TMS is inferred from a careers-page reference, not confirmed by the company\n- Newest news item is 140 days old, so no in-window event exists\n- No evidence on renewal timing\n\n---\nSources used: company_research, icp_score, tech_signals, job_signals, news_signals",
"confidence": "high",
"evidence": [
"job_signals.implied_initiatives[0] — 'six of nine open engineering roles reference carrier API integration'",
"job_signals.hiring_velocity.open_roles_total — 9",
"tech_signals.normalized_stack[2] — 'legacy TMS inferred from a careers-page tooling reference'",
"company_research.buying_committee_shape — 'Operator-led evaluation with finance sign-off above roughly EUR 100k annual spend.'",
"icp_score.band — 'Tier A'"
],
"data_gaps": ["contact_profile absent", "news_signals newest item is 140 days old, past max_age_days; the Series B is out-of-window context only"]
}
headline is one sentence, maximum 120 characters, and must contain at least one specific fact rather than a category label. priority is high, medium, or low, derived from the rubric below. why_now is 2-4 sentences, maximum 500 characters, and must reference at least one dated or recent signal or explicitly state that no timing signal exists. talking_points holds exactly 3 objects when inputs allow and fewer when they do not, each with point (one sentence, max 160 characters), evidence (a short quote or value from the input), and source_field (a dotted path into the input object). discovery_questions holds exactly 2 open questions, each one sentence, neither answerable with yes or no. likely_objection holds objection (the words the buyer would actually use), basis (the input fields that predict it), and counter_angle (one sentence of framing, not a script). first_touch_angle is 1-2 sentences naming what to lead with and, where useful, what to avoid. unknowns holds up to 6 items, each naming a missing input or a low-confidence upstream field. input_coverage is a boolean map of which optional inputs were present. rendered_markdown is the full human-readable brief as a single string following references/brief-template.md, with real newlines escaped as \n. confidence, evidence (max 5 items), and data_gaps (empty array when nothing was missing) are required.
input_coverage first. Missing inputs are not a reason to write less carefully; they are a reason to write a longer unknowns list.confidence: "low" is usable but must be labeled. A fact from a low-confidence upstream field may appear in a talking point only if the point is hedged in the same sentence ("their careers page suggests...") and the field is named in unknowns. Never launder a low-confidence upstream field into a high-confidence brief sentence.company_research.canonical_domain against the domain or company reference on every other input. If any input references a different company, drop that input entirely, set its input_coverage value to false, and record the mismatch in data_gaps. Merging a tech stack from the wrong company is the single most damaging failure this skill can produce, because the rep will say it out loud.max_age_days beats undated beats stale), specificity (a countable fact beats a category beats an adjective), and actionability (something the buyer is currently spending money or headcount on beats something they merely are). Sort descending. The top signal becomes the headline and anchors why-now; signals two through four become talking points. Anything below that is discarded, not appended.priority drops accordingly.news_signals events, then job_signals initiatives, then company_research.funding_trajectory, then tech_signals changes. If nothing in the inputs describes a change, say so explicitly: "No timing signal in the available inputs; this is a fit-based rather than event-based reason to call." That sentence is more valuable to a rep than a manufactured urgency.source_field is a dotted path into the input objects, and evidence is the value or a short quote from it. Before you emit a point, re-read its source field and confirm the point does not overstate it. If you cannot name the path, the point does not ship. This is the single rule that makes the skill safe to run unattended.basis, and give one sentence of reframing in counter_angle — a framing, not a rebuttal script, since scripted rebuttals belong to objection-handler.call_type: cold_outbound needs a reason for the interruption, discovery needs the question to open on, demo needs what to show first, renewal_expansion needs the change since last cycle, event_followup needs the callback to the shared context.null, "unknown", or low-confidence, and questions your own talking points raise but cannot answer. Write each as something a rep could go find, not as an abstract lament. Cap at 6, ordered by how much the brief would improve if resolved.references/brief-template.md exactly and derive every line from a field already in the object. Do not add a sentence to the rendered version that does not exist in the structured fields, and do not drop a field to make it read better. The two representations must be checkable against each other.company_research at medium or better plus at least three optional inputs present plus a dated why-now signal inside max_age_days. Medium is company_research plus one or two optional inputs, or a full set where the why-now is stale. Low is company_research alone, or any brief where a contradiction between inputs remains unresolved.| Rule | Behavior |
|---|---|
| No new facts, ever | Every noun and number in the output exists in an input. You may compress, order, and reframe. You may not add, extrapolate a trend, estimate a figure, or infer a competitor. |
| Every point names its field | A talking point without a valid source_field is deleted, not weakened. Three good points beat three points plus one guess. |
| No fresh research | Do not call search, fetch, or any enrichment tool even if available. If the inputs are thin, the brief says so. |
| Contradictions surface, never merge | When two inputs disagree, prefer the more recent, then the more primary, and write both values into data_gaps. Never average, never pick silently. |
| Hedge inherits upward | A hedged upstream field stays hedged in the brief and its uncertainty appears in unknowns. |
| No filler questions | A discovery question that works for any account in the segment is cut and the field carries one question rather than two. |
| Buyer's words for objections | likely_objection.objection is phrased as the buyer would say it, in first person, not as a category name. |
| Length caps hold | Headline 120 characters, why-now 500, each talking point 160, each question 200. Truncate at sentence boundaries. |
| Both views agree | rendered_markdown contains no claim absent from the structured fields, and omits no structured field the template calls for. |
| No vendor claims | Never assert what the seller's product does beyond what seller_context states. Without it, points describe the account, not the fit. |
priority is derived, not judged. Evaluate the low row first: any condition in it forces low regardless of band. Otherwise take high if its condition holds, and medium for everything else.
| Priority | Condition |
|---|---|
low |
A disqualifier is present (icp_score.disqualified is true or icp_score.disqualifier_reason is non-null), or company_research.confidence is low, or no input contains a specific fact. |
high |
icp_score.band is Tier A or Tier B, and at least one signal is dated inside max_age_days. |
medium |
Everything else — including a Tier A or Tier B band with no in-window signal, and an in-window signal with no icp_score supplied. |
Inputs: company_research (Aldervoort Freight Systems, confidence high, logistics SaaS in Rotterdam, quote-based, sales-led, buying_committee_shape operator-led with finance sign-off above roughly EUR 100k), icp_score (band: "Tier A", disqualified: false, breakdown cites headcount and GTM motion), tech_signals (normalized_stack[2] a legacy TMS at evidence_strength: "inferred", a workflow tool at confirmed), job_signals (hiring_velocity.open_roles_total 9, six of them referencing carrier API integration, all posted within 60 days), news_signals (Series B, days_since: 140, still_actionable: false), no contact_profile, seller_context present, call_type: "cold_outbound", max_age_days: 90.
priority is high because the band is Tier A and the postings are dated inside max_age_days. The raise is 140 days old, so the rubric on stale inputs bars it from the headline and from why_now; it survives only as the thing the rep is told not to open with.
{
"headline": "Six of nine open engineering roles reference carrier API work, alongside a detected legacy TMS.",
"priority": "high",
"why_now": "Six of nine open engineering roles were posted inside the last 60 days and every one references carrier API integration, which job-signal analysis flags as the stated bottleneck. A legacy TMS is detected alongside a workflow tool, though that detection is inferred from a careers-page reference rather than confirmed. That combination puts them in a build-or-buy window on exactly the surface we replace.",
"talking_points": [
{"point": "Carrier integration is their current constraint, not a nice-to-have.", "evidence": "job_signals.implied_initiatives[0] — 'six of nine open engineering roles reference carrier API integration'", "source_field": "job_signals.implied_initiatives[0]"},
{"point": "A legacy TMS is detected alongside a workflow tool, so the integration burden looks real and duplicated.", "evidence": "tech_signals.normalized_stack[2] — 'legacy TMS inferred from a careers-page tooling reference', evidence_strength 'inferred'", "source_field": "tech_signals.normalized_stack[2]"},
{"point": "Buying is operator-led with finance sign-off above EUR 100k, so a scoped pilot clears without procurement.", "evidence": "company_research.buying_committee_shape — 'Operator-led evaluation with finance sign-off above roughly EUR 100k annual spend.'", "source_field": "company_research.buying_committee_shape"}
],
"discovery_questions": [
"When you scoped the six integration hires, what was the alternative you priced against?",
"Who owns the carrier-API roadmap today — the platform team or ops?"
],
"likely_objection": {
"objection": "We just funded a team to build this in-house.",
"basis": "job_signals.implied_initiatives[0] plus company_research.funding_trajectory",
"counter_angle": "Reframe around time-to-first-carrier rather than build capability; their own roles are dated within the last quarter."
},
"first_touch_angle": "Lead with the six integration roles and ask what they priced the build against. Do not open with the funding round; it closed 140 days ago and everyone opens with it anyway.",
"unknowns": [
"No contact_profile supplied; title-level framing is inferred from company_research.likely_buyer_titles",
"Legacy TMS carries evidence_strength 'inferred' from a careers-page reference, not confirmed by the company",
"news_signals newest item is 140 days old, so no in-window event exists",
"No evidence on renewal timing"
],
"input_coverage": {"company_research": true, "icp_score": true, "tech_signals": true, "job_signals": true, "news_signals": true, "contact_profile": false},
"rendered_markdown": "## Aldervoort Freight Systems — pre-call brief\n\n**Six of nine open engineering roles reference carrier API work, alongside a detected legacy TMS.**\n\nPriority: high | Confidence: high | Call type: cold_outbound\n\n### Why now\nSix of nine open engineering roles were posted inside the last 60 days and every one references carrier API integration, which job-signal analysis flags as the stated bottleneck. A legacy TMS is detected alongside a workflow tool, though that detection is inferred from a careers-page reference rather than confirmed. That combination puts them in a build-or-buy window on exactly the surface we replace.\n\n### Talking points\n1. **Carrier integration is their current constraint, not a nice-to-have.**\n Evidence: six of nine open engineering roles reference carrier API integration\n2. **A legacy TMS is detected alongside a workflow tool, so the integration burden looks real and duplicated.**\n Evidence: legacy TMS inferred from a careers-page tooling reference\n3. **Buying is operator-led with finance sign-off above EUR 100k, so a scoped pilot clears without procurement.**\n Evidence: operator-led evaluation with finance sign-off above roughly EUR 100k annual spend\n\n### Ask these\n- When you scoped the six integration hires, what was the alternative you priced against?\n- Who owns the carrier-API roadmap today — the platform team or ops?\n\n### Expect this objection\n\"We just funded a team to build this in-house.\"\n\nReframe around time-to-first-carrier rather than build capability; their own roles are dated within the last quarter.\n\n### Open with\nLead with the six integration roles and ask what they priced the build against. Do not open with the funding round; it closed 140 days ago and everyone opens with it anyway.\n\n### What we still don't know\n- No contact profile supplied; title-level framing is inferred from likely buyer titles\n- Legacy TMS is inferred from a careers-page reference, not confirmed by the company\n- Newest news item is 140 days old, so no in-window event exists\n- No evidence on renewal timing\n\n---\nSources used: company_research, icp_score, tech_signals, job_signals, news_signals",
"confidence": "high",
"evidence": [
"job_signals.implied_initiatives[0] — 'six of nine open engineering roles reference carrier API integration'",
"job_signals.hiring_velocity.open_roles_total — 9",
"tech_signals.normalized_stack[2] — 'legacy TMS inferred from a careers-page tooling reference'",
"company_research.buying_committee_shape — 'Operator-led evaluation with finance sign-off above roughly EUR 100k annual spend.'",
"icp_score.band — 'Tier A'"
],
"data_gaps": ["contact_profile absent", "news_signals newest item is 140 days old, past max_age_days; the Series B is out-of-window context only"]
}
Inputs: company_research only (confidence low, offline run, dry-dock maintenance services, ~200 people, Halifax, quote-based, sales-led), nothing else, call_type: "cold_outbound".
{
"headline": "Halifax dry-dock maintenance provider, roughly 200 staff, no recent public signals available.",
"priority": "low",
"why_now": "No timing signal exists in the available inputs. The only research artifact is a low-confidence offline profile with no dated events, no hiring data, and no technology detection. Treat this as a fit-based call rather than an event-based one, and expect to earn the why-now on the call itself.",
"talking_points": [
{"point": "Their profile reports quote-based pricing at low confidence, so per-job estimating is plausibly manual — ask, do not assert.", "evidence": "company_research.pricing_model — 'quote_based'; company_research.confidence — 'low'", "source_field": "company_research.pricing_model"}
],
"discovery_questions": [
"How long does it take you to get from an inbound enquiry to a firm quote today?",
"Who decides whether a job is worth quoting at all?"
],
"likely_objection": {
"objection": "I've never heard of you and I don't know why you're calling.",
"basis": "Absence of any signal input; company_research.confidence is low",
"counter_angle": "Do not claim a trigger you do not have; open on the quoting workflow and ask rather than assert."
},
"first_touch_angle": "Lead with a question about quote turnaround time, not with a claim about their business. There is nothing in the inputs specific enough to earn a claim.",
"unknowns": [
"No news_signals, job_signals, tech_signals, icp_score, or contact_profile supplied",
"company_research ran offline; headcount is an unverified secondhand claim",
"No domain confirmed, so account identity is unverified"
],
"input_coverage": {"company_research": true, "icp_score": false, "tech_signals": false, "job_signals": false, "news_signals": false, "contact_profile": false},
"rendered_markdown": "## Harbourline Marine Services — pre-call brief\n\n**Halifax dry-dock maintenance provider, roughly 200 staff, no recent public signals available.**\n\nPriority: low | Confidence: low | Call type: cold_outbound\n\n### Why now\nNo timing signal exists in the available inputs. The only research artifact is a low-confidence offline profile with no dated events, no hiring data, and no technology detection. Treat this as a fit-based call rather than an event-based one, and expect to earn the why-now on the call itself.\n\n### Talking points\n1. **Their profile reports quote-based pricing at low confidence, so per-job estimating is plausibly manual — ask, do not assert.**\n Evidence: quote-based pricing, research confidence low\n\n### Ask these\n- How long does it take you to get from an inbound enquiry to a firm quote today?\n- Who decides whether a job is worth quoting at all?\n\n### Expect this objection\n\"I've never heard of you and I don't know why you're calling.\"\n\nDo not claim a trigger you do not have; open on the quoting workflow and ask rather than assert.\n\n### Open with\nLead with a question about quote turnaround time, not with a claim about their business. There is nothing in the inputs specific enough to earn a claim.\n\n### What we still don't know\n- No news, hiring, technographic, ICP, or contact inputs supplied\n- Research ran offline; headcount is an unverified secondhand claim\n- No domain confirmed, so account identity is unverified\n\n---\nSources used: company_research",
"confidence": "low",
"evidence": [
"company_research.pricing_model — 'quote_based'",
"company_research.employee_count_estimate — 200, employee_count_basis 'operator_context'",
"company_research.confidence — 'low'"
],
"data_gaps": [
"Only one of six inputs supplied",
"One talking point rather than three; no second or third defensible axis existed in the single supplied input",
"Account identity unverified upstream"
]
}
One point, not three. The headcount observation that would have padded this to two is true of every 200-person company, so it is not a claim the rep can defend and it does not ship.
Inputs: company_research (Brackwell Yard Services, confidence medium, employee_count_estimate: 85, employee_count_basis: "directory"), job_signals (hiring_velocity.open_roles_total: 40, growth_signals[0] showing twelve of those roles under operations, and evidence[2] quoting a posting line "you'll join our team of 300"), icp_score (disqualified: true, band: "Disqualified", disqualifier_reason naming a 100-employee floor), nothing else, call_type: "cold_outbound".
The brief keeps the account live and surfaces the contradiction rather than resolving it invisibly. The rubric forces priority: "low" because a disqualifier is present, and confidence is "low" despite three inputs because the unresolved contradiction bears directly on whether the call should happen at all. The verification step is the first line of unknowns so it is read before the dial.
{
"headline": "Forty open roles and a posting citing a 300-person team, against a directory headcount of 85.",
"priority": "low",
"why_now": "Forty roles are open now and twelve of them sit under operations, which is a change rather than a state. The two headcount figures disagree, though: company_research reports 85 employees on a directory basis while a posting tells candidates they will join 'our team of 300'. Resolve the headcount before treating this as a qualified why-now, because the ICP disqualifier turns on the 85 figure and would not fire on 300.",
"talking_points": [
{"point": "They are opening forty roles at once, twelve in operations, which is a hiring push whatever the true headcount turns out to be.", "evidence": "job_signals.hiring_velocity.open_roles_total — 40; job_signals.growth_signals[0] — twelve roles under operations, direction 'expanding'", "source_field": "job_signals.hiring_velocity.open_roles_total"}
],
"discovery_questions": [
"What changed operationally that made twelve operations roles worth opening in the same quarter?",
"Who is absorbing the work those forty roles are meant to cover until they are filled?"
],
"likely_objection": {
"objection": "We're a lot smaller than that hiring page makes us look.",
"basis": "icp_score.disqualifier_reason plus company_research.employee_count_estimate against job_signals.evidence[2]",
"counter_angle": "Do not argue the headcount; ask what the forty roles are meant to absorb and let their answer set the size."
},
"first_touch_angle": "Lead with the twelve operations roles and ask what they are meant to absorb. Say nothing about company size until the headcount conflict is resolved.",
"unknowns": [
"Verify current headcount before routing: 85 on a directory basis against 'our team of 300' in a posting; ICP band may flip",
"employee_count_basis is 'directory', the weakest basis available",
"No news_signals, tech_signals, or contact_profile supplied"
],
"input_coverage": {"company_research": true, "icp_score": true, "tech_signals": false, "job_signals": true, "news_signals": false, "contact_profile": false},
"rendered_markdown": "## Brackwell Yard Services — pre-call brief\n\n**Forty open roles and a posting citing a 300-person team, against a directory headcount of 85.**\n\nPriority: low | Confidence: low | Call type: cold_outbound\n\n### Why now\nForty roles are open now and twelve of them sit under operations, which is a change rather than a state. The two headcount figures disagree, though: company_research reports 85 employees on a directory basis while a posting tells candidates they will join 'our team of 300'. Resolve the headcount before treating this as a qualified why-now, because the ICP disqualifier turns on the 85 figure and would not fire on 300.\n\n### Talking points\n1. **They are opening forty roles at once, twelve in operations, which is a hiring push whatever the true headcount turns out to be.**\n Evidence: 40 open roles, twelve under operations, direction expanding\n\n### Ask these\n- What changed operationally that made twelve operations roles worth opening in the same quarter?\n- Who is absorbing the work those forty roles are meant to cover until they are filled?\n\n### Expect this objection\n\"We're a lot smaller than that hiring page makes us look.\"\n\nDo not argue the headcount; ask what the forty roles are meant to absorb and let their answer set the size.\n\n### Open with\nLead with the twelve operations roles and ask what they are meant to absorb. Say nothing about company size until the headcount conflict is resolved.\n\n### What we still don't know\n- Verify current headcount before routing: 85 on a directory listing against 'our team of 300' in a posting; ICP band may flip\n- Headcount basis is a directory listing, the weakest basis available\n- No news, technographic, or contact inputs supplied\n\n---\nSources used: company_research, icp_score, job_signals",
"confidence": "low",
"evidence": [
"job_signals.hiring_velocity.open_roles_total — 40",
"job_signals.evidence[2] — posting line 'you will join our team of 300'",
"company_research.employee_count_estimate — 85, employee_count_basis 'directory'",
"icp_score.disqualifier_reason — 'Employee count 85 is below the 100-employee floor'"
],
"data_gaps": [
"Headcount conflict: company_research.employee_count_estimate 85 (directory basis) vs a job_signals posting quoting 'our team of 300'; the ICP disqualifier turns on the 85 figure and would not fire on 300",
"One talking point rather than three; the only environmental fact available is the contradicted headcount"
]
}
When company_research is absent or empty, refuse rather than improvise from whatever else arrived. Emit the total-failure row: headline: null, priority: "low", why_now: null, talking_points: [], discovery_questions: [], likely_objection: null, first_touch_angle: null, unknowns: ["No company_research input supplied"], input_coverage reflecting reality, rendered_markdown: null, confidence: "low", evidence: [], and data_gaps: ["Cannot compose a brief without company_research"]. A brief assembled from a tech stack and a job board with no verified account identity is a liability, not a shortcut.
When inputs contradict, the contradiction is the finding. Follow the recency-then-primacy order to decide which value leads the brief, put both values in data_gaps, and drop confidence by one level. If the contradiction affects whether the rep should call at all — a disqualifying ICP score against strong buying signals, or a size mismatch — say so in the first line of unknowns so it is read before the dial.
Non-English source material may appear inside upstream evidence strings. Quote it verbatim in evidence and source_field references, and render the brief itself in US English. Do not translate company names, product names, or job titles that would lose meaning; gloss them in parentheses once if the rep would otherwise misread them.
Stale inputs are demoted, not deleted. Any signal older than max_age_days is barred from why_now and from the headline, may still appear as a talking point when it is structural rather than temporal, and is named with its age in unknowns. A brief whose newest signal is eleven months old should say "no recent signal" in why-now even when the inputs are otherwise rich, because a rep who opens on stale news loses the call in the first sentence.
Placeholder and test rows arrive here as upstream refusals rather than raw junk. When company_research itself returned a placeholder refusal, or when the account name matches test, example, asdf, or a single character, emit the total-failure row with data_gaps: ["Upstream input appears to be a placeholder or test row"] and do not attempt to compose around it.
contact_profile is the one input carrying personal data, and it is used only to shape framing: seniority, function, tenure, and stated professional focus. Do not restate personal details, do not reference anything that could identify protected characteristics, do not quote personal posts as evidence of intent, and never write a talking point whose premise is something the person disclosed about themselves rather than about their work. When contact_profile is absent, infer nothing about the individual and fall back to company_research.likely_buyer_titles with that substitution named in unknowns.
When the honest answer is that there is not enough to say, say less. A brief with two talking points, a why-now that admits no trigger exists, and a three-item unknowns list is a good output. Padding to three points with a generic observation is the failure mode this skill exists to prevent, because the rep cannot tell which of the three is the invented one.
Sample 20 briefs and check each of the following. Every source_field resolves to a real path in the supplied inputs, and the value at that path actually supports the point. No sentence anywhere in the output introduces a company, product, number, person, or event absent from the inputs. Every why_now either cites a signal dated within max_age_days or explicitly states that no timing signal exists. No two talking points in the same brief sit on the same axis. Neither discovery question is answerable with yes or no, and neither would read as sensible for a randomly chosen different account in the same segment. Every absent optional input appears in both input_coverage as false and in unknowns or data_gaps. rendered_markdown contains no claim absent from the structured fields. No brief is confidence: "high" while carrying an unresolved contradiction or fewer than three optional inputs. Every output parses as JSON on the first attempt with no fence, preamble, or trailing text.
Use an AI / Claude column and map the upstream skills' parsed output columns into the input fields by name — this column reads only from your table, so it should be the last column in the enrichment order and should never have web search enabled. Parse the response into subfields so headline, priority, first_touch_angle, and rendered_markdown land in their own columns; rendered_markdown is the one reps actually copy into a call note or a CRM activity, so keep it in a wide text column rather than a truncated preview. Because it does no research, it is one of the cheapest columns in the pack, but it is also the most sensitive to upstream quality, so gate it behind a filter that requires company_research.confidence to be medium or better and the ICP band to be within your calling range. Running it across an entire list wastes tokens on accounts nobody will call; run it on the working queue for the week instead. Route any brief with confidence: "low" or a non-empty contradiction gap to a manager review view before it reaches a rep.