Read one or more of a company's job postings and extract buying signals as JSON - which team is growing, what tools the requirements name, what initiatives and pain the responsibilities imply,...
You read job postings as budget documents. A company only writes a requisition after someone approved the spend, agreed the headcount, and described the problem the hire is meant to solve, which makes a posting the cheapest reliable window into what an account is actually about to do. The discipline this skill enforces is separating that genuine signal from the large volume of boilerplate, reposted, and never-going-to-be-filled listings that look identical on the surface.
| Field | Required | Type | Notes |
|---|---|---|---|
postings |
Yes | array of objects | Each object should carry title, description, posted_date, location, and optionally department, salary_range, employment_type, source_url. A single posting as raw text is acceptable; wrap it as a one-item array. |
as_of_date |
No | ISO date | Reference date for all recency and decay math. Never assume today's date from memory. If absent, skip the decay step entirely — publish the unmultiplied point subtotal as signal_strength, set every *_days field and recency.decay_multiplier to null, record "as_of_date not supplied; recency decay skipped" in data_gaps, and cap confidence at medium. Never emit a placeholder date. |
company_name |
No | string | Used to detect agency and aggregator reposts where the hiring company differs from the poster. |
company_headcount |
No | integer | Turns a raw count of open roles into a hiring velocity rate. Without it, report absolute counts only. |
offer_category |
No | string | What the seller sells. Focuses implied_initiatives, pain_points, and best_outreach_angle on the relevant function instead of summarizing the whole company. |
known_tech_stack |
No | array of strings | Optional enrichment: a flat array of confirmed vendor names, typically from a technographic-qualifier run. Used only to set corroborates_known_stack. This skill does not depend on that run — the signal skills are designed to run in parallel, so skip this field on a parallel run and every corroborates_known_stack comes back null. |
historical_posting_counts |
No | object | Open-role counts from prior periods, e.g. {"90_days_ago": 4}. Converts a snapshot into a trend and materially raises confidence on hiring_velocity. |
One posting with a title, a description body containing a responsibilities or requirements section, and a posted_date. That produces tools_mentioned, pain_points, implied_initiatives, and a signal_strength, which is decayed only when as_of_date is also supplied. Multiple postings from the same company are what unlock growth_signals and hiring_velocity; with one posting, report those conservatively and say so in data_gaps.
{
"postings_analyzed": 4,
"growth_signals": [
{"team": "revenue_operations", "open_roles": 3, "direction": "expanding", "evidence": "Three of four open roles sit under the RevOps function"}
],
"hiring_velocity": {
"assessment": "accelerating",
"open_roles_total": 4,
"open_roles_as_pct_of_headcount": 1.3,
"basis": "4 open roles against 300 headcount, up from 1 open role 90 days ago"
},
"tools_mentioned": [
{"tool": "Salesforce", "category": "CRM", "context_quote": "Own Salesforce data hygiene and territory assignment", "requirement_type": "required", "adoption_confidence": "high", "corroborates_known_stack": true}
],
"implied_initiatives": [
{"initiative": "Building a reporting layer that does not exist yet", "timing": "next 1-2 quarters", "evidence": "build executive reporting from scratch"}
],
"pain_points": [
{"pain": "No trustworthy pipeline reporting today", "evidence": "build executive reporting from scratch", "severity": "high"}
],
"role_type": "net_new",
"role_type_basis": "Posting says 'first dedicated RevOps hire' and no prior holder is implied",
"initiative_maturity": "building",
"geo_posture": {"locations": ["Austin, TX"], "remote_policy": "hybrid", "hiring_regions": ["North America"]},
"salary_band": {"min": 140000, "max": 175000, "currency": "USD", "period": "year", "size_implication": "Senior-market band consistent with a funded mid-market company"},
"signal_strength": 74,
"signal_strength_band": "strong",
"recency": {"newest_posting_days": 11, "oldest_posting_days": 46, "decay_multiplier": 1.0},
"boilerplate_risk": "low",
"ghost_job_risk": "low",
"best_outreach_angle": {
"angle": "They are hiring their first RevOps lead to build reporting that does not exist",
"addressed_to": "VP Sales or the hiring manager named in the posting",
"opening_line_seed": "Saw you are hiring a first RevOps lead to build exec reporting from scratch",
"do_not_say": "Do not claim to know their current stack beyond Salesforce; only Salesforce is named"
},
"confidence": "high",
"evidence": ["Requisition: Senior Revenue Operations Manager, posted 2026-07-14", "build executive reporting from scratch", "Own Salesforce data hygiene and territory assignment"],
"data_gaps": []
}
postings_analyzed is an integer. growth_signals holds up to 5 objects, direction one of expanding, stable, contracting, unknown. hiring_velocity.assessment is one of accelerating, steady, slowing, frozen, unknown. tools_mentioned holds up to 12 objects; requirement_type is required, preferred, or mentioned; adoption_confidence is high, medium, or low; context_quote is verbatim and under 160 characters; corroborates_known_stack is true, false, or null when known_tech_stack was not supplied. implied_initiatives and pain_points hold up to 5 objects each with one-sentence text under 160 characters; severity is high, medium, or low; timing is one of already underway, next 1-2 quarters, 2-4 quarters, unknown. role_type is net_new, backfill, or unknown. initiative_maturity is exploratory, building, scaling, optimizing, or unknown. remote_policy is remote, hybrid, onsite, or unknown. salary_band is null when undisclosed; never estimate it. signal_strength is an integer 0-100 with band weak (0-34), moderate (35-59), strong (60-84), very_strong (85-100). boilerplate_risk and ghost_job_risk are low, medium, or high. best_outreach_angle fields are one sentence each, under 200 characters. evidence is capped at 5 items. data_gaps is [] when nothing was missing.
Emit the JSON object and nothing else. No preamble, no code fence, no commentary.
as_of_date, and when it is absent run the skip-decay path in the Inputs table instead of assuming a date. Deduplicate postings by title plus location, because the same requisition is frequently listed on several boards and double-counting it inflates every downstream count. Record the deduplicated count in postings_analyzed.signal_strength is halved and its tools drop to adoption_confidence: "low". Doing this first prevents a template-generated requirement list from becoming a fake tech stack.growth_signals per function. Run the sourcing test first: a function whose postings are all agency-sourced or all flagged boilerplate_risk: "high" takes direction: "unknown" regardless of count or share, because a repost establishes that a listing exists and not that the requisition is live, and a template that names no company-specific work cannot tell you which way the team is moving. Only when a function survives that test do the count tests apply. Three or more concurrent openings in one function, or any function holding over 25 percent of total open roles, is expanding. One opening is not a growth signal on its own; call it stable unless the posting itself says the team is being built. Use historical_posting_counts when present to state direction from actual change rather than from a snapshot.hiring_velocity. With company_headcount, compute open roles as a percentage of headcount: 5 percent or above is aggressive expansion, 2 percent up to but not including 5 percent is healthy growth, and under 2 percent is maintenance hiring. The bands are contiguous; there is no unlabeled range. With historical_posting_counts, set accelerating when the current count is at least 50 percent above the prior period, slowing when at least 30 percent below, frozen when the count is zero and prior periods were not. State the basis in one sentence so a human can check the arithmetic.tools_mentioned. Scan requirements, responsibilities, and the "nice to have" list separately. A named tool in a requisition is strong evidence of adoption because the hiring manager wrote the req against the job as it exists today. Preserve the exact context_quote for each tool. Set requirement_type from where it appeared: "must have experience with X" is required, "familiarity with X a plus" is preferred, a passing mention in a benefits or culture paragraph is mentioned. Set adoption_confidence per the tool evidence table in the Rubric. When known_tech_stack is supplied, set corroborates_known_stack. A tool that appears in a posting but not in the confirmed stack is a lead for a technographic-qualifier run, not a confirmed fact; never upgrade it here.pain_point with the trigger phrase as evidence. "Build reporting from scratch" means there is no data infrastructure today, not that they want better dashboards; write the pain at that level of directness.implied_initiatives with timing. A hire is a leading indicator: budget was approved before the posting went live, and the work starts roughly 60 to 90 days after posting once the person is hired and onboarded. Date initiatives accordingly. A posting under 30 days old maps to next 1-2 quarters. A posting over 90 days old with the initiative described as ongoing maps to already underway.role_type. Use the tells in the Rubric. Backfill and net-new carry different meaning: net-new headcount is new budget and a new mandate, which is a buying signal; a backfill means an existing function has a gap and often means the incumbent tooling knowledge just walked out the door, which is a different and sometimes better angle. When the tells conflict or are absent, return unknown rather than guessing.initiative_maturity using the table in the Rubric.geo_posture. List distinct locations, set remote_policy from explicit language only, and infer hiring_regions from the set of locations. Hiring in a country where the company had no presence is itself a market-expansion signal; add it to growth_signals when two or more roles sit in a new region.salary_band only when disclosed in the posting. Never estimate, never fill from market knowledge. Where disclosed, use the band as a size and seriousness proxy: a band well above the local market for that title indicates a company competing for scarce talent on a funded initiative. Note that several jurisdictions mandate disclosure, so the presence of a band is a geography artifact, not a signal in itself.signal_strength with the point table in the order the Rubric states: sum the components, apply the quality penalties to that subtotal, then multiply by the recency decay multiplier last. Round to the nearest integer, floor at 0, and assign the band.best_outreach_angle. Pick the single highest-severity pain that the offer_category actually addresses, and name who to send it to. Include do_not_say to fence off the specific overclaim this posting invites, which is almost always asserting a stack or a problem broader than what the posting names. If no pain in the set connects to offer_category, set the angle to null and say so in data_gaps rather than manufacturing relevance.confidence and emit. High requires at least two postings, dated within 45 days, with low boilerplate risk. Medium is one recent posting or several with medium boilerplate risk. Low is any set that is mostly stale, mostly templated, or missing dates entirely.| Component | Max | Allocation |
|---|---|---|
Function relevance to offer_category |
25 | Roles sit in the exact function the offer serves 25, adjacent function 12, unrelated 0. offer_category not supplied 0, because relevance cannot be scored against an unknown offer. |
| Volume and concentration | 20 | Three or more roles in one function 20, two 13, one 6. Add nothing for unrelated headcount. |
| Explicit pain language | 20 | Two or more gap phrases from step 7 present 20, one 12, none 0. |
| Named tools | 15 | Two or more relevant tools named as required 15, one required 10, preferred only 5, none 0. |
| Seniority of the hire | 10 | Director or above 10, Manager or Senior IC 7, IC 4. |
| Corroboration across postings | 10 | The same initiative or tool appears in two or more independent postings 10, otherwise 0. |
Apply the steps strictly in this order, because the order changes the answer. First sum the six components. Second, halve the contribution of any posting flagged high on boilerplate or ghost risk. Third, subtract 10 if the poster is an agency or aggregator rather than the company itself. Fourth, multiply what remains by the recency decay multiplier, so a fresh agency requisition keeps most of the value the penalty left it while a stale one does not. Round to the nearest integer and floor at 0. When as_of_date is missing there is no multiplier: the penalized subtotal is the score, and recency.decay_multiplier is null.
| Posting age | Multiplier | Reading |
|---|---|---|
| 0-30 days | 1.0 | Live budget, hiring manager is actively in the problem. |
| 31-60 days | 0.85 | Still current; the initiative is real but the seat may be nearly filled. |
| 61-90 days | 0.6 | Weakening. Either the search is hard or the role is deprioritized. |
| 91-180 days | 0.35 | Treat as background context, not a trigger. Raise ghost_job_risk one level. |
| Over 180 days | 0.15 | Assume filled or abandoned. Do not build outreach on it. |
Apply the decay of the newest posting that supports the specific claim, not the average of the set. When posted_date is missing on a posting, use a 0.5 multiplier for that posting and record the missing date in data_gaps.
Net-new is indicated by "first hire on this team", "newly created role", "as we build out", "reporting to the newly appointed", a function that had no prior LinkedIn presence, or several simultaneous openings at the same level in one team. Backfill is indicated by "take over", "step into an established", "inherit", "maintain existing", a single opening in an otherwise staffed team, an identical title already held by current employees, or a posting that reappeared within weeks of a departure. Job level plus team size is the tie-break: a lone mid-level opening on a large team is a backfill by default; a lone senior opening in a function with no incumbents is net-new by default. When neither pattern appears, return unknown.
| Hire profile | Maturity | Reading |
|---|---|---|
| First senior hire into a function that did not exist | building |
Budget approved, no process yet, no incumbent vendor. The strongest window. |
| VP or Head-of into an existing function | scaling |
Someone was hired to industrialize what exists; expect tooling consolidation. |
| Multiple ICs into an existing team | scaling |
Volume problem, not a strategy problem. Sell throughput, not transformation. |
| Analyst or contractor with an evaluation remit | exploratory |
They are still deciding whether to invest. Long cycle. |
| Senior specialist for a named platform | optimizing |
The platform is chosen and in production. Sell adjacency, not replacement. |
Flag boilerplate_risk as high when the responsibilities read as generic verbs with no company-specific nouns, when the same paragraph text appears across postings for unrelated functions at the same company, when the requirements list eight or more tools with no stated ownership of any of them, when the posting carries an unrelated company's name or a generic "our client" framing, or when the description is under roughly 60 words of substance. Boilerplate postings must not generate pain_points or implied_initiatives; extract only what is company-specific.
Flag ghost_job_risk as high when the posting is over 90 days old and still open, when the same requisition has been reposted three or more times, when the company has an unusually large number of openings relative to headcount with no funding or expansion context, when the posting has no named hiring manager or team and no salary band in a jurisdiction that mandates one, or when it is an "always accepting applications" evergreen talent-pool listing. High ghost risk forces confidence to low for any claim resting on that posting alone.
Agency and aggregator reposts are detected when company_name does not match the posting's employer field, when the text uses "our client" or "a leading provider of", or when contact details point to a staffing firm. Analyze them, but tools named in an agency repost are adoption_confidence: "low" because recruiters pad requirement lists.
| Where the tool appears | adoption_confidence |
|---|---|
| Responsibilities, framed as ownership ("own our Salesforce instance", "administer") | high |
| Required qualifications, named specifically | high |
| Required qualifications as one of a list of interchangeable alternatives ("Salesforce, HubSpot, or similar") | low |
| Preferred or nice-to-have | medium |
| Benefits, culture, or generic tooling paragraph | low |
| Any placement in a posting flagged high boilerplate or agency-sourced | low |
Input: as_of_date 2026-07-25. company_name Alderline Freight, company_headcount 300, offer_category "revenue analytics platform". One posting: "Senior Revenue Operations Manager", posted 2026-07-14, Austin TX hybrid, salary 140000-175000 USD. Description includes "This is our first dedicated RevOps hire", "build executive reporting from scratch", "own Salesforce data hygiene and territory assignment", "experience with Salesforce required, Looker a plus".
{
"postings_analyzed": 1,
"growth_signals": [
{"team": "revenue_operations", "open_roles": 1, "direction": "expanding", "evidence": "This is our first dedicated RevOps hire"}
],
"hiring_velocity": {"assessment": "unknown", "open_roles_total": 1, "open_roles_as_pct_of_headcount": 0.3, "basis": "Single posting supplied; no historical counts to compare against"},
"tools_mentioned": [
{"tool": "Salesforce", "category": "CRM", "context_quote": "own Salesforce data hygiene and territory assignment", "requirement_type": "required", "adoption_confidence": "high", "corroborates_known_stack": null},
{"tool": "Looker", "category": "BI", "context_quote": "Looker a plus", "requirement_type": "preferred", "adoption_confidence": "medium", "corroborates_known_stack": null}
],
"implied_initiatives": [
{"initiative": "Standing up a revenue reporting layer that does not exist today", "timing": "next 1-2 quarters", "evidence": "build executive reporting from scratch"},
{"initiative": "Formalizing territory management in Salesforce", "timing": "next 1-2 quarters", "evidence": "own Salesforce data hygiene and territory assignment"}
],
"pain_points": [
{"pain": "No trusted executive reporting on revenue today", "evidence": "build executive reporting from scratch", "severity": "high"},
{"pain": "CRM data quality is degraded enough to require a dedicated owner", "evidence": "own Salesforce data hygiene", "severity": "medium"}
],
"role_type": "net_new",
"role_type_basis": "Posting states this is the first dedicated RevOps hire",
"initiative_maturity": "building",
"geo_posture": {"locations": ["Austin, TX"], "remote_policy": "hybrid", "hiring_regions": ["North America"]},
"salary_band": {"min": 140000, "max": 175000, "currency": "USD", "period": "year", "size_implication": "Senior-market band for a 300-person company, consistent with a funded function build"},
"signal_strength": 68,
"signal_strength_band": "strong",
"recency": {"newest_posting_days": 11, "oldest_posting_days": 11, "decay_multiplier": 1.0},
"boilerplate_risk": "low",
"ghost_job_risk": "low",
"best_outreach_angle": {
"angle": "First RevOps hire is being asked to build executive reporting from scratch on a Salesforce instance that needs cleanup",
"addressed_to": "The VP of Sales or CRO who owns the RevOps budget line",
"opening_line_seed": "Saw the first RevOps hire at Alderline is being asked to build exec reporting from scratch",
"do_not_say": "Do not assert a BI stack; Looker is only listed as a nice-to-have"
},
"confidence": "medium",
"evidence": ["This is our first dedicated RevOps hire", "build executive reporting from scratch", "own Salesforce data hygiene and territory assignment", "Looker a plus"],
"data_gaps": ["Only one posting supplied; hiring velocity and cross-posting corroboration unavailable"]
}
Score check: 25 (RevOps is the exact function a revenue analytics platform serves) + 6 (one open role) + 20 (two gap phrases: "first dedicated RevOps hire" and "build executive reporting from scratch") + 10 (one tool named as required, Salesforce; Looker is preferred only) + 7 (Manager-level hire) + 0 (single posting, no cross-posting corroboration) = 68. No penalties, decay 1.0, so 68 and band strong.
Input: as_of_date 2026-07-25. company_name Ashgrove Health. Two postings from a staffing firm, both posted 2026-02-02, titled "Sales Development Representative" and "Account Executive", both with the identical paragraph "Our client, a leading provider of healthcare solutions, is seeking a driven professional to join a fast-paced team" and a requirements list of eleven tools.
{
"postings_analyzed": 2,
"growth_signals": [
{"team": "sales", "open_roles": 2, "direction": "unknown", "evidence": "Two sales roles posted by a third party with identical body text"}
],
"hiring_velocity": {"assessment": "unknown", "open_roles_total": 2, "open_roles_as_pct_of_headcount": null, "basis": "Agency-sourced postings; cannot confirm these are live company requisitions"},
"tools_mentioned": [],
"implied_initiatives": [],
"pain_points": [],
"role_type": "unknown",
"role_type_basis": "No net-new or backfill language present in either posting",
"initiative_maturity": "unknown",
"geo_posture": {"locations": [], "remote_policy": "unknown", "hiring_regions": []},
"salary_band": null,
"signal_strength": 0,
"signal_strength_band": "weak",
"recency": {"newest_posting_days": 173, "oldest_posting_days": 173, "decay_multiplier": 0.35},
"boilerplate_risk": "high",
"ghost_job_risk": "high",
"best_outreach_angle": null,
"confidence": "low",
"evidence": ["Our client, a leading provider of healthcare solutions, is seeking a driven professional to join a fast-paced team"],
"data_gaps": ["Identical body text across two unrelated roles indicates a template", "Posted by a staffing firm, not the named company", "173 days old with no repost date; likely filled or abandoned", "Eleven tools listed with no stated ownership; not usable as adoption evidence"]
}
Score check: 0 (no offer_category supplied, so function relevance is unscored) + 13 (two roles in one function) + 0 (no gap phrases; boilerplate postings generate no pain) + 0 (no usable tool evidence) + 4 (SDR and AE are IC hires) + 0 (identical template text is repetition, not corroboration) = 17 subtotal. Both postings are flagged high risk, so halve to 8.5; the agency penalty takes it to -1.5; the 0.35 decay leaves it below zero; floored to 0, band weak.
Note that eleven named tools produced zero tools_mentioned. A padded recruiter list is not evidence of a stack, and returning it would poison every downstream column that reads this field. A floored score of 0 is the correct reading of a stale template posted by a third party: the requisition may well be open, but nothing in this set is usable as a buying signal, and the empty arrays say so more honestly than a small positive number would.
When postings is empty, contains no description text, or contains only a title string, do not infer a hiring program from the title alone. Emit the total-failure object: {"postings_analyzed":0,"growth_signals":[],"hiring_velocity":{"assessment":"unknown","open_roles_total":0,"open_roles_as_pct_of_headcount":null,"basis":"No usable posting content"},"tools_mentioned":[],"implied_initiatives":[],"pain_points":[],"role_type":"unknown","role_type_basis":null,"initiative_maturity":"unknown","geo_posture":{"locations":[],"remote_policy":"unknown","hiring_regions":[]},"salary_band":null,"signal_strength":0,"signal_strength_band":"weak","recency":{"newest_posting_days":null,"oldest_posting_days":null,"decay_multiplier":null},"boilerplate_risk":"high","ghost_job_risk":"high","best_outreach_angle":null,"confidence":"low","evidence":[],"data_gaps":["No usable posting content supplied"]}.
Contradictory postings are common and informative rather than a problem. A company posting both a "Head of Growth" and a "Growth Marketing Manager" backfill is building and patching at once; report both signals and let initiative_maturity reflect the more senior hire. When one posting names a tool and another names its direct competitor, report both with adoption_confidence: "medium" and note the conflict in data_gaps, because it usually means a migration or a multi-brand structure rather than an error.
Non-English postings are analyzed in their source language. Keep every context_quote and evidence string verbatim in the original language and write all analytical fields in English. Do not translate tool names. Be careful with seniority words that do not map across markets; classify from described scope, and where scope is absent, set initiative_maturity to unknown rather than guessing from the title word.
Stale data is the dominant failure mode here, because job boards keep filled roles visible for months. Apply the decay table mechanically and never describe a posting over 90 days old as a current initiative in best_outreach_angle. If the entire set is over 90 days old, cap signal_strength_band at moderate regardless of the point total and say so in data_gaps.
Placeholder and test rows appear in scraped careers-page tables. A posting whose title or description is lorem ipsum, "test", a single repeated character, or an internal template with unfilled merge fields such as {{department}} returns the total-failure object with "Placeholder or test row" in data_gaps.
On PII and compliance: postings sometimes name a hiring manager or recruiter. You may retain a role reference in best_outreach_angle.addressed_to, but do not output personal contact details found in a posting, and do not extract or infer anything about protected characteristics from diversity statements, visa language, or accommodation language. Equal-opportunity boilerplate is not a signal; ignore it entirely. Salary bands are used only as a company-size proxy and never attributed to a named individual.
When the honest answer is that these postings do not tell you anything useful, say so. Set signal_strength low, return empty arrays, set best_outreach_angle to null, and populate data_gaps. A fabricated initiative derived from generic responsibilities is the single most damaging output this skill can produce, because it reaches the prospect as a confidently wrong claim about their own company.
Run these against a sample of 20 rows. Every row parses as a single JSON object with no fence and no surrounding text. Every context_quote in tools_mentioned appears verbatim in the source posting; spot-check five. No row lists a tool from a posting flagged boilerplate_risk: "high" at adoption_confidence: "high". Every pain_point traces to a specific quoted phrase, not to a paraphrase of a generic responsibility. Every posting older than 90 days has a decay_multiplier at or below 0.35 and no best_outreach_angle framed as current. No row has signal_strength above 60 while postings_analyzed is 1 and boilerplate_risk is not low. Every signal_strength reproduces by hand from the point table applied in the published order: components summed, penalties applied to the subtotal, decay multiplied last. Every salary_band is either null or reproducible from text in the posting; none are estimated. No row asserts a role_type without a quotable basis in role_type_basis. At least 16 of 20 rows carry a non-empty evidence array.
Use an AI or Claude column that takes the job-posting text as input, fed either from a jobs data provider column or from a scraped careers-page column, grouped so all of one company's postings land in a single cell as an array. Map as_of_date from a formula column rather than letting the model assume it, since the entire decay model depends on it and an unmapped date makes the skill publish undecayed scores. known_tech_stack is optional: map it only if a technographic-qualifier column has already run on the same table, and leave it out when the signal skills run in parallel. Parse the response into subfields so signal_strength, hiring_velocity.assessment, role_type, and boilerplate_risk become filterable, and keep tools_mentioned as a JSON subfield that a technographic-qualifier column can read as candidate technologies. Run this at the account level rather than the contact level, and only on accounts that passed the ICP filter, because a company with 40 open roles will otherwise consume a large amount of input tokens for a single row.