Localized offer letter generation
LLM drafts country-specific offer letters with required clauses from a template library.
HR processPlanSourceSelectHireOnboardDevelopRewardExit
By Don, DoneThat’s AI coach · updated
The draft must cite the template and the range
A quality draft names the country template it used and the approved compensation range it drew pay from. If a required clause is missing from that template, the slot stays empty. Recruiting operations still sends the letter. The model does not send it, and it does not invent a statutory clause to look complete.
Traceability is the bar, not speed. Ops should answer two questions from the draft before a candidate sees it: which template version, and which approved range. Without those answers, the file is unattributed employment prose, not an offer draft.
HRIS, ATS, e-sign, and contract systems (Workday, Greenhouse, DocuSign, Ironclad as a class) already hold the offer, the template, and the send path. The model is a drafter between them. It is not the system of record.
Load the country template and the approved offer first
Do not start from a prompt like "write an offer letter for Germany." Load two artifacts before any sentence is generated: the country template from the library, and the approved offer from the hiring record.
The template is counsel-owned, versioned, and keyed to a jurisdiction. It may also key to legal entity, contract type, or a union overlay. Required clauses come only from this file. The approved offer supplies role, start date, location, compensation, equity, and signed-off exceptions. If either artifact is missing, stop.
Compensation must come from the same approved record a comp recommendation per offer would have produced or confirmed. Do not take a figure from recruiter chat, a verbal "we can do 95," or a stale spreadsheet. If pay sits outside the approved range, leave pay fields blank rather than rounding them into compliance.
Screening contingencies belong in the letter only when the template already contains them. Cite open checks from background-check risk extraction as status. Do not rewrite them as homemade legal conditions.
Illustrative example: recruiting ops in a Berlin entity needs a letter for a senior engineer. The approved offer is EUR 92,000 base, 10 percent bonus target, start date 1 October. Germany full-time template v14 requires probation length, notice periods, a working-time reference, and a data-protection notice. The model loads DE-FT-v14 and the approved offer, fills those slots from offer fields, and stamps two ops cites: "Template: DE-FT-v14" and "Comp: approved range EUR 88,000-96,000; this offer EUR 92,000 base." The template has no works-council co-determination block for this entity, so that block stays empty. Ops does not send until employment counsel supplies the clause or confirms it does not apply.
Draft with cites; leave required clauses blank
Every generated letter needs two cites in an ops-only header or footer: country template id and version, and the approved compensation range plus the figures taken from it.
A letter with no template cite is a failed generation. Do not polish it. Do not load it into an envelope. Reload the template and generate again.
Copy required clauses from the loaded template only. Bind variables (dates, amounts, titles) from the approved offer. If someone insists "France always needs X" and X is not in the template, leave the section blank. Inventing a statutory clause is a quality failure even when the invented sentence later looks roughly right. Roughly right is not counsel-approved.
The correct signal is visible emptiness: a labeled blank, a comment, or a note that the clause is not present in template DE-FT-v14. Fluent invented law hides the miss until a candidate has signed.
If the approved offer lacks a field the template requires, leave that field blank too. Do not infer a bonus percentage because the rest of the team has one. Do not copy the last candidate. A blank in the draft is cheaper than a wrong number sitting in DocuSign.
Language that belongs in the employment agreement rather than the offer letter should go through contract clause review. Shared topics such as IP, non-solicit, and benefits do not mean shared approval. Mixing them is how a friendly draft becomes an unauthorized contract.
Recruiting ops sends; generation is not release
The model produces a draft. Recruiting ops or employment ops is the sender. Keep that split as a hard control.
Do not auto-send. Do not wire "generation succeeded" to the e-sign envelope as one unattended step. Workday, Greenhouse, DocuSign, and Ironclad can route, store, or collect signature. None of that should turn a finished draft into a notified candidate.
Treating the draft as sent is the failure mode that looks like efficiency. A recruiter forwards a complete-looking PDF, or a workflow emails the candidate when the generator returns text. The person then holds language never checked against the template version, the approved range, or a blank required clause. Recall is slow. The record is already wrong.
Before send, ops confirms the template cite matches work country and hiring entity (not only residence); the comp cite matches the approved offer; every required-clause slot is filled from the template or visibly blank and accepted by counsel; no statutory sentence appears that was not in the template; and the send in the ATS or e-sign tool is a separate, human-triggered action.
If you use an offer-acceptance probability model, keep it off the letter. It can tell ops to escalate a range exception. It must not rewrite clauses or add sweeteners the approved offer does not contain.
Refuse uncited drafts, auto-send, and invented law
A letter with no template cite means the model wrote fluent employment prose from general knowledge. You cannot tell whether Germany, Austria, or a US at-will pack shaped the notice period. Block output unless template load succeeded.
Treating the draft as sent: keep generated files internal until a human sends from the ATS or e-sign tool. The generation job must not email the candidate.
Inventing a statutory clause: models will "know" paid-leave language or a probation cap for a country. If that language is not in the loaded template, it does not belong in the letter. A hallucinated clause is worse than a blank. It looks official, it can conflict with the actual contract, and it may be wrong for the entity.
Quieter variants to block: wrong country because residence and hiring entity differ; clauses copied from the last candidate in the same role; pay filled from a recruiting range instead of the approved offer; a US template auto-translated into another language and labeled localized. Localization is template selection plus variable binding, not translation of last quarter's US letter.
Counsel owns the library; ops owns the send
Counsel owns clause text and version dates. Recruiting ops owns the generation run and the send. Key the library by country, and by entity when one country has more than one employment vehicle.
For each offer the run is the same: resolve country and entity, load that template version, load the approved offer, generate with cites, review blanks, send only after human confirmation.
When a country is new, do not ask the model to bootstrap a statutory pack. Add a template first, even a short one, with required-clause slots named. Until that template exists, there is no quality draft, only a risk of invented law.
Judge the process by cite presence, by blanks that stay blank when the template is silent, and by whether anyone sent a letter without a template cite. Time-to-first-draft is not a quality measure.
Is this worth automating for you?
Whether this pays back depends on how much time it takes your team today. Most teams estimate that from memory, and the estimate is usually wrong in one direction or the other.
DoneThat reconstructs where the time actually went, with no timers to forget, so you can measure the baseline before committing to a project and check the gain afterward.
Measure the baseline first