play icon for videos
← Academy
SOPACT ACADEMY · CASE INTELLIGENCE · COLLECT

Turn a Job Description into a Requirements Checklist

Every job description parsed on arrival into a requirements checklist — each item flagged hard or coachable against the start date, and every unfilled role given a named reason.

<aside class="ci-wizard" aria-label="Case Intelligence series navigator"> <div class="ci-wiz-eyebrow">The Case Intelligence Series</div> <div class="ci-wiz-sub">13 chapters · foundation + two tracks</div> <div class="ci-progress"><span style="width:67%"></span></div> <div class="ci-progress-label">You're here — Chapter 10 of 13</div> <div class="ci-group">Foundation</div> <ol class="ci-steps"> <li class="ci-step is-done"> <a href="/academy/what-is-case-intelligence" target="_blank" rel="noopener"> <span class="ci-num">1</span> <span class="ci-step-body"><span class="ci-step-title">What Is Case Intelligence?</span></span> </a> </li> <li class="ci-step is-done"> <a href="/academy/how-to-build-a-theory-of-change" target="_blank" rel="noopener"> <span class="ci-num">2</span> <span class="ci-step-body"><span class="ci-step-title">How to Build a Theory of Change That Survives Funder Questions</span></span> </a> </li> <li class="ci-step is-done"> <a href="/academy/theory-of-change-to-data-collection-workflow" target="_blank" rel="noopener"> <span class="ci-num">3</span> <span class="ci-step-body"><span class="ci-step-title">How to Turn a Theory of Change into a Data-Collection Workflow</span></span> </a> </li> </ol> <div class="ci-group">Nonprofit Track</div> <ol class="ci-steps"> <li class="ci-step "> <a href="/academy/review-applications-without-reviewer-bias" target="_blank" rel="noopener"> <span class="ci-num">4</span> <span class="ci-step-body"><span class="ci-step-title">How to Review Applications Without Reviewer Bias</span></span> </a> </li> <li class="ci-step "> <a href="/academy/intake-form-usable-baseline" target="_blank" rel="noopener"> <span class="ci-num">5</span> <span class="ci-step-body"><span class="ci-step-title">How to Design an Intake Form That Captures a Usable Baseline</span></span> </a> </li> <li class="ci-step "> <a href="/academy/spot-at-risk-participants-mid-program" target="_blank" rel="noopener"> <span class="ci-num">6</span> <span class="ci-step-body"><span class="ci-step-title">How to Spot At-Risk Participants Mid-Program</span></span> </a> </li> <li class="ci-step "> <a href="/academy/measure-change-at-exit" target="_blank" rel="noopener"> <span class="ci-num">7</span> <span class="ci-step-body"><span class="ci-step-title">How to Measure Change at Exit (Not Just Completion)</span></span> </a> </li> <li class="ci-step "> <a href="/academy/mentor-notes-early-warning" target="_blank" rel="noopener"> <span class="ci-num">8</span> <span class="ci-step-body"><span class="ci-step-title">How to Catch At-Risk Participants Early with Mentor Notes</span></span> </a> </li> <li class="ci-step "> <a href="/academy/calculate-sroi-live" target="_blank" rel="noopener"> <span class="ci-num">9</span> <span class="ci-step-body"><span class="ci-step-title">How to Calculate SROI — Live, Sourced, and Honest</span></span> </a> </li> <li class="ci-step "> <a href="/academy/cohort-to-funder-impact-report" target="_blank" rel="noopener"> <span class="ci-num ci-num-range">12a</span> <span class="ci-step-body"><span class="ci-step-title">How to Turn a Cohort into a Funder Impact Report</span></span> </a> </li> </ol> <div class="ci-group">Social Enterprise Track</div> <ol class="ci-steps"> <li class="ci-step is-active" aria-current="step"> <span class="ci-num ci-num-range">10</span> <span class="ci-step-body"><span class="ci-step-title">How to Turn a Job Description into a Requirements Checklist</span><span class="ci-step-meta">You're here</span></span> </li> <li class="ci-step "> <a href="/academy/score-candidate-role-matches-without-bias" target="_blank" rel="noopener"> <span class="ci-num ci-num-range">11</span> <span class="ci-step-body"><span class="ci-step-title">How to Score Candidate–Role Matches Without Bias</span></span> </a> </li> <li class="ci-step "> <a href="/academy/cohort-to-investor-impact-report" target="_blank" rel="noopener"> <span class="ci-num ci-num-range">12b</span> <span class="ci-step-body"><span class="ci-step-title">How to Turn a Cohort into a Social-Enterprise Investor Report</span></span> </a> </li> </ol> <a class="ci-next" href="/academy/score-candidate-role-matches-without-bias" target="_blank" rel="noopener">Continue to Chapter 11 &nbsp;→</a> </aside> <style> .ci-wizard{--ink:#48416A;--body:#3D3A33;--muted:#76716A;--surface:#F7F6FD;--surface2:#EFEAFB;--line:#E4DFF2;--line2:#DCCEF4;--accent:#8D8AE8; position:sticky;top:24px;box-sizing:border-box;font-family:'Inter',system-ui,sans-serif;color:var(--body); background:var(--surface);border:1px solid var(--line);border-radius:14px;padding:22px 20px;} .ci-wizard *{box-sizing:border-box;} .ci-wiz-eyebrow{font-family:'Inter',Georgia,serif;font-size:18px;font-weight:600;color:var(--ink);line-height:1.25;} .ci-wiz-sub{font-size:12.5px;color:var(--muted);margin-top:3px;} .ci-progress{height:5px;border-radius:999px;background:var(--surface2);margin:14px 0 7px;overflow:hidden;} .ci-progress span{display:block;height:100%;background:var(--accent);border-radius:999px;} .ci-progress-label{font-size:12px;color:var(--muted);} .ci-group{font-size:11px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--muted);margin:18px 0 8px;padding-top:14px;border-top:1px solid var(--line);} .ci-group:first-of-type{border-top:0;} .ci-steps{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:2px;} .ci-step a,.ci-step{display:flex;gap:12px;align-items:flex-start;text-decoration:none;color:inherit;} .ci-step a{padding:8px;margin:-8px;border-radius:10px;transition:background .15s;width:100%;} .ci-step a:hover{background:var(--surface2);} .ci-step{padding:8px 0;} .ci-num{flex:0 0 auto;width:26px;height:26px;border-radius:50%;display:grid;place-items:center;font-size:12.5px;font-weight:600;color:var(--muted);background:var(--surface2);border:1px solid var(--line2);} .ci-num-range{width:auto;min-width:26px;padding:0 9px;border-radius:999px;font-size:11.5px;height:26px;} .ci-step-title{display:block;font-size:14px;font-weight:500;color:var(--ink);line-height:1.35;} .ci-step-meta{display:block;font-size:11.5px;color:var(--muted);margin-top:2px;} .ci-step.is-active .ci-num{background:var(--accent);border-color:var(--accent);color:#fff;box-shadow:0 0 0 4px rgba(201,100,66,.15);} .ci-step.is-active .ci-step-title{font-weight:600;} .ci-step.is-active .ci-step-meta{color:var(--accent);font-weight:600;} .ci-step.is-done .ci-num{background:var(--ink);border-color:var(--ink);color:#fff;} .ci-next{display:flex;align-items:center;justify-content:center;margin-top:20px;background:var(--ink);color:#fff;text-decoration:none;font-size:14px;font-weight:600;padding:12px 16px;border-radius:11px;transition:transform .15s,background .15s;} .ci-next:hover{background:var(--accent);transform:translateY(-1px);} </style>

For: placement and matching teams — workforce programs matching trainees to roles, fellowships matching fellows to host sites, accelerators matching founders to partners — who inherit every opportunity description as a paragraph of prose.

Why: a job description is a free-text blob, so matching against it is manual keyword guesswork — slow, inconsistent between coordinators, and a place where bias hides, because the reasons a candidate was passed over are never written down.

Outcome: every requisition parsed on arrival into a structured requirements checklist — each item flagged HARD (disqualifying) or COACHABLE (trainable before the start date), each role scored for fill-difficulty, and every unfilled job given a named reason.

What happens the moment a requisition arrives:

  • Intelligent Cell parses every job description on arrival — free-text prose converted into a structured checklist, each requirement flagged HARD (disqualifying) or COACHABLE (trainable before the start date), with the source line quoted.
  • Intelligent Row gives every role its own profile — one row per requisition: requirements, fill-difficulty score, days open, and the named reason if it's still unfilled.
  • Ask the demand side anything, in plain English — the Sopact assistant cuts across every requisition and your candidate pool at once: "Which open roles could our current cohort fill after one certification?" — from Sense, or from Claude or ChatGPT via MCP.
  • Hard-to-fill roles raise their own hand — when Intelligent Cell scores a requisition as high-difficulty or spots a requirement your pipeline can't meet, you're notified automatically, months before the start date makes it a crisis.

This is Chapter 10 of the Case Intelligence series — and the first chapter on the demand side. In Chapter 9 you computed a live, sourced SROI over the supply-side stores; every chapter so far has been about participants. But placement is a two-sided market, and the other side arrives as prose. Whether your participants are trainees, students, founders, or grantees, the method is identical.

As always, the first two steps are [DIY] — designing the schema and parsing one job description are thinking work for any AI chat window. The last two are [SENSE] — because parsing every requisition as it lands, and lining all of them up against a credentialed pool, needs the stores a chat window has never seen.

A job description is prose — and prose can't be matched

Here is how a requisition arrives: a paragraph. "Seeking a welding apprentice, must be authorized to work in the US, valid driver's license required, OSHA 30 preferred, able to lift 50 lbs, start by November 15." A coordinator reads it, forms a rough mental picture, and eyeballs candidates against the picture. In most placement operations that is the entire matching process, and it fails three ways.

It is slow: every role gets re-read from scratch for every candidate considered — twenty candidates against one role means twenty re-readings of the same paragraph. It is inconsistent: two coordinators weigh "OSHA 30 preferred" differently, so the same candidate is qualified on Tuesday and unqualified on Wednesday, and nobody can say why. And it is where bias hides: when requirements live in someone's head, the reasons for a pass-over are never written down — "not a fit" is the phrase that ends the conversation and erases the evidence.

One design decision does most of this chapter's work: every extracted requirement gets one of two flags. HARD means disqualifying — citizen-only work authorization cannot be coached; a commercial driver's license the program does not train for cannot be earned in three weeks. COACHABLE means trainable in time — a missing OSHA 30 that takes about two weeks is not a rejection, it is a two-week plan, provided the start date allows it. Downstream, the split is what keeps matching humane; in aggregate, it is what makes unfilled demand diagnosable, because the question that matters about a stalled role is which hard requirement blocked it.

Step 1 — Design the requirement schema [DIY]

Decide once the fixed set of categories every requirement falls into — credential, license, work authorization, background, deadline — and the single rule that classifies each one: a requirement is HARD if no coaching before the deadline can satisfy it; otherwise it is COACHABLE. Notice the rule is relative to the deadline, not the requirement — the same missing certificate is coachable in September and hard on November 10. That relativity is why the deadline is a schema category, not a footnote.

Here are the roles I place for — tracks, typical employers, typical requirements — and what my program can train or coach, and how fast: [paste both].

Design my requirement schema. Start from five categories — credential, license, work authorization, background, deadline — and add one only if a recurring requirement fits none of them, quoting the requirement that forced it. List each category's values as a closed set. Then apply the one rule — a requirement is HARD if no coaching before the deadline can satisfy it, otherwise COACHABLE — and tell me which of my values are structurally hard. Working conditions like "lift 50 lbs" are disclosures, not requirements — keep them out of matching.

Keep the schema small. Five categories that hold ninety-five percent of requirements beat fourteen that each hold one — a schema that grows a category per unusual role stops being a schema and becomes prose with extra steps.

Step 2 — Parse one job description by hand [DIY]

Take one real open role and parse its free text into the schema yourself before anything runs at scale — the same calibration move as scoring one application before trusting a rubric with the pool. If a real requirement fits no category, you have found a schema problem on one role instead of after a hundred extractions.

Here is my schema, what my program can train and how fast, and one real job description exactly as the employer sent it: [paste all three].

Parse every requirement into the schema and flag each one HARD or COACHABLE by the rule — can coaching close it before the start date? — not by the employer's word choice: "required" is not automatically hard, and "preferred" is not automatically coachable. Quote the employer's exact phrase next to every flag, and if a coachable gap can't close before the deadline, re-flag it hard and say why. Route working conditions to a disclosures line, and if a requirement fits no category, write SCHEMA GAP instead of forcing it.

The line that earns its keep is the soft one. The welder requisition says "OSHA 30 preferred but we'll train" — a coordinator in a hurry reads "OSHA 30" and rejects a candidate who could have been ready in two weeks. The rule reads the deadline and says COACHABLE, with the employer's own words attached as evidence.

Step 3 — Every requisition structured on arrival [SENSE]

From here on, this is what the product does — not a prompt you run. A chat window parses the one job description you paste; the product holds the requisition store, so the extraction fires on every role as it lands — the first employer's requisition and the fortieth structured against the identical schema. It also computes the one field a chat window never could: fill-difficulty, which requires knowing how rare each hard requirement is in your credentialed pool. Here is the welder requisition, structured the moment it landed:

One requisition · structured the moment it lands (welding apprentice, start Nov 15)
RequirementFlagEmployer's exact phrase
AWS D1.1 certificationHARD"AWS D1.1 certification required"
Driver's licenseHARD"Valid driver's license required (no CDL)"
Work authorizationHARD"Must be authorized to work in the US"
BackgroundHARD"Clean background for site access"
OSHA 30COACHABLE · ~2 weeks"OSHA 30 preferred but we'll train"
Fill-difficultyMODERATEHard requirements common among credentialed candidates
Read it: the prose says "preferred" — the rule says coachable against the Nov 15 start, with the employer's own words attached. A coordinator in a hurry rejects that candidate; the checklist can't.

Every flag carries the employer's phrase, so any classification can be audited in seconds. And the fill-difficulty score is an early-warning system: a citizen-only, clearance-eligible analyst role gets flagged hard-to-fill the day it lands — before a single candidate is proposed, not after six weeks of quiet failure. Tune the hard-versus-coachable rule on your first five or ten requisitions and everything already in the store re-extracts against the revised rule — early and late roles structured identically.

Step 4 — Surface the supply/demand gap [SENSE]

The second thing no standalone prompt can do: line up every open requisition against every credentialed candidate at once. In Sense you ask across the stores in plain language:

  • "Which hard requirements leave roles unfilled?" — the stalled requisitions clustered by the requirement that blocks them, not listed as individual failures.
  • "Where is supply surplus?" — the tracks with more credentialed candidates than open roles this quarter.
  • "Which open roles will be hardest to fill from this pool?" — fill-difficulty ranked from day one, so nobody discovers a doomed requisition in week six.
  • "Turn each cluster into the action it implies" — recruit or train for the blocking requirement on one side; develop employer demand or throttle intake on the other.
The supply/demand gap · requisitions vs the credentialed pool
SideFindingRoute to
Unfilled demand25 requisitions blocked by HARD FAILS — clustered on citizen-only work authorization and CDL licenses the program doesn't trainRecruit for cleared-role tracks; evaluate adding a CDL track
Surplus supply29 credentialed candidates SURPLUS — more welders and CNAs than open roles this quarterOpen new employer demand; throttle intake until it catches up
Early warningCitizen-only analyst role flagged HIGH fill-difficulty the day it landedSet expectations before six weeks of quiet failure
Read it: the 29 surplus candidates did everything asked of them. The gap is a pattern with named fixes on both sides — not a training failure.

Sit with what that table is not saying: it is not saying the program trained people badly. The 29 surplus candidates are credentialed — they did everything asked of them. The gap is a misalignment on two named, structural requirements, and each half points at a specific decision. Without structured requirements, the same reality is 25 individual disappointments and 29 individual frustrations, and the pattern connecting them stays invisible — which is exactly how it stays unfixed for years. The next chapter turns this checklist and that pool into candidate-by-role match scores.

Common mistakes

Treating every "required" in the prose as hard. Employers write "required" loosely — the welder requisition marks OSHA 30 "preferred but we'll train." Flag by the rule, and keep the employer's phrase attached as evidence.

Classifying without the deadline. Coachable is a race against the start date, not a property of the requirement. A checklist with no deadline field makes every coachable flag a guess.

Letting the schema grow a category per role. When a requirement doesn't fit, first ask whether it is really a requirement — "able to lift 50 lbs" is a working condition to disclose, not a match criterion to score.

Rejecting candidates for coachable gaps. The split exists so a two-week gap becomes a two-week plan. Treat COACHABLE flags as soft rejections and you have rebuilt the old bias with better paperwork.

Skipping the employer join. A requisition with no employer name and no requisition ID is an orphan — it can never reconcile with placements, so you can never learn which employers' roles fill and which stall. The reference keys are why the unfilled pattern is computable at all.

What you have now

A fixed five-category schema with one mechanical hard-versus-coachable rule. Every job description parsed into a checklist on arrival, each item flagged, each employer's own wording preserved as evidence. A fill-difficulty score that warns about hard-to-fill roles the day they land. And across the stores, the demand gap as a named pattern — 25 unfilled requisitions traced to citizen-only and CDL hard fails, 29 surplus credentialed candidates traced to thin employer demand — each half pointing at a specific action.

The one thing to do this week

Take your most recent open role — the actual description, as the employer sent it — and parse it with the Step 2 prompt. Flag each requirement against the real start date, then show the checklist to whoever does your matching. If they disagree with a flag, you have found the inconsistency that was already happening silently between coordinators. One structured role is the seed of the demand side.

Who this is for

Placement coordinators who re-read the same job description twenty times a season and carry the requirements in their heads. Programs whose employer partnerships produce requisitions nobody can systematically match against. Directors who suspect their unfilled roles share a cause but can't name it. If a candidate was ever rejected for a certification they could have earned before the start date, the fix starts here.

Structure your demand side in Sopact Sense — sopact.com/academy.

Next in the series: How to Score Candidate–Role Matches Without Bias — the checklist you built meets the credentialed pool, and every candidate–role pair gets a scored, auditable match with the gap named.

Ready to try it for yourself?

Open Sopact Sense, paste your program description, and put it to work.

Try it in Case Intelligence →