Deep dive: LLM pipeline

4,455 military job codes, translated into tech careers

A veteran types in their military job code and gets a guide to the tech roles it maps to, with skills, certifications and salary data that names its source.

  • 4,455job codes indexed across five service branches
  • 4,201codes with a generated tech pathway (94%)
  • 35tech roles in the taxonomy, each with a BLS SOC code
  • 0model calls at request time
Role
Designed and built the pipeline and the pages that render it
Stack
TypeScript, Vercel AI SDK, Zod schemas, Google Gemini, Next.js static generation
Model
gemini-2.0-flash, named in each generator script
Data
Lightcast, Census ACS 2023 estimates, a curated fallback table
Shipped
Pathways generator merged 2 May 2026 (#1104)

The problem

A military job code tells a civilian recruiter almost nothing. A veteran leaving the service knows what they did, and usually does not know which software roles value it or what those roles pay. Vets Who Code answers that question one conversation at a time. There are thousands of job codes across the Army, Navy, Air Force, Marine Corps and Coast Guard, and nobody can hold all of them in their head.

What it has to do

  • Cover every code it can. A veteran who looks up their own code should find it.
  • Return the same structure every time. Pages are generated from the data, so free-form model output is not acceptable.
  • Say where each salary came from. A veteran is making a career decision on these numbers.
  • Cost nothing per page view. The organization cannot pay for a model call each time someone reads a guide.

Approach and architecture

The pipeline runs offline in stages. Each stage reads the previous stage’s JSON, asks Gemini for an object that must match a Zod schema, and writes JSON back to the repository. The site then builds static pages from those files.

Pipeline: job code text files are parsed into an index, four Gemini steps generate skill, systems, training and certification maps, a pathways step joins them with a role taxonomy and salary data, and the site renders static career guides. Job codes parsed, no LLM Gemini + Zod cognitive skills military systems training pipeline cert equivalencies career pathways 35-role taxonomy Tech pathways resumable join Salary data Static guides + gap report
Every box writes JSON to the repository. The final step also produces a curriculum gap report.

Data model

FileKeyed byEntries
job-codes-index.jsonJob code4,455
cognitive-skills-map.jsonJob code4,392
military-systems-map.jsonJob code4,386
cert-equivalencies.jsonJob code4,350
career-pathways-map.jsonJob code4,231
training-pipeline.jsonJob code4,203
tech-pathways-map.jsonJob code, joined to role and salary4,201
tech-roles-taxonomy.jsonRole, with BLS SOC code35

Key tradeoffs

Generate offline, commit the output

Model output is generated ahead of time and reviewed as a diff, then served as static pages. A guide loads with no model latency and no token cost, and a model outage cannot take a page down. The cost is freshness: a guide is as current as the last run. Recorded as DR-005.

Salary data falls back in three tiers and labels itself

The pipeline asks Lightcast first, then Census ACS, then a curated table. Each record carries a dataSource field so the page can show which tier answered. The pipeline always completes, and a reader can tell a live figure from a curated one. Recorded as DR-006.

Small batches, resumable runs

Generators work in batches of 10 with a one-second pause, and the pathways step merges into existing output. A failed run resumes where it stopped instead of paying to regenerate four thousand entries.

Measurable outcome

  • 4,201 job codes have a published guide with roles, certifications, demand and salary.
  • Each guide carries Occupation structured data so search engines and AI assistants can read it (#1407).
  • The same data produces a curriculum gap report that ranks tech roles by how many job codes map to them. Data Analyst leads with 3,796 codes, then Security Engineer with 3,723.

Evals, cost, latency, fallback and limits

EvalsOutput is validated against a Zod schema on every call. There is no labelled accuracy set yet. See v2.
CostZero at request time. Generation cost per run is not recorded yet.
LatencyZero model latency for readers. Pages are static.
FallbackSalary: Lightcast, then Census ACS, then curated. Generation: resumable from existing output.
Known limits254 indexed codes have no tech pathway. Mappings are model-generated and schema-checked, and have not been reviewed code by code by a subject-matter expert.

AI collaboration note

The model writes the per-code content. I own the schemas that constrain it, the role taxonomy it has to map into, the salary sourcing and the decision about what gets published. Generated files are committed and reviewed like any other change.

What I’d change in v2

  • Build an accuracy set. Have veterans from each branch grade a sample of guides for their own job codes, and track the score across model versions.
  • Record tokens and cost for each generation run alongside the output.
  • Move the model name to one shared constant. It is currently repeated in each script.
  • Close the 254-code gap or state on the page why a code has no pathway.

Walk me through it

  1. Why job code translation is the first question every transitioning veteran asks.
  2. The stages, and why each one writes a file a person can read.
  3. How a Zod schema turns a language model into a function with a return type.
  4. The three salary tiers and why the page shows which one answered.
  5. What the gap report shows about demand by role.
  6. What is not measured yet, and how I would measure it.