<job/syntax>
first public draft, 2026-07-19. markdown made prose portable; jobsyntax does the same for job postings.
a posting is three things: a header block of key: value lines, one blank line, and a prose body. two readers with equal rights: a person typing into a bare textarea with no docs open, and an agent parsing with one regex.
role: senior backend engineer company: northwind logistics location: remote (canada) type: full-time level: senior comp: 140000-170000 cad/year skills: go, postgres, kubernetes, event sourcing apply: [email protected] you would own the dispatch service - the thing that decides which truck gets which load, twenty thousand times a day. mostly go against a large postgres instance, with an event log we replay for audits.
one field per line key: value keys lowercase, ^[a-z][a-z0-9-]*$ parse with ^([a-z][a-z0-9-]*):[ \t]*(.*)$ order free, except a submission starts with role: continuation lines none. one line per field. unknown keys parse fine, get dropped by the normalizer encoding utf-8, unix newlines header ends at the first blank line
required (5) role, company, location, comp, apply
optional (4) type full-time | contract | part-time | internship
level junior | mid | senior | staff | lead
skills comma-separated, lowercase
comp is free text; canonical form 140000-170000 cad/year
server (3) id, posted, expires — stamped on acceptance, never
typed. submissions arriving with them are rejected.comp is required. a posting that hides pay is an ad, not an offer. boards that let salary hide are optimizing for the poster; this board reads like the seeker. ranges are fine. hiding is not.
free prose, 40–1500 characters, no markup. the body is not decoration — it is the matching payload. titles lie; the work does not. describe the actual work, and the matching engine can find the people one lateral hop away.
the whole live board ships at /jobs.txt: a comment preamble (lines starting with #), then records separated by a line that is exactly %%. served records lead with the server fields, so a record starts at an id: line. body lines that would collide with %% or the key pattern are prefixed with one space. externally observed jobs are a separate stream with the same grammar at /wire.txt.
paste a messy posting at /post and it gets rewritten into this shape before it goes live — that is the whole trick. the spec stays small because the normalizer absorbs the mess.
v0.1 · 2026-07-19 · changes to the format will be listed here.