Capture
JD → jd.md
A pasted job description becomes a versioned markdown file with metadata, role family inference, and the verbatim copy. Every claim downstream traces here.
An agentic AI workflow built on Claude Code and MCP. Specialised agents, a constitutional rule file, and hooks that enforce between sessions. Everything traces to a source on disk, nothing is invented.
Role family 1
Primary target lane
Role family 2
Secondary target lane
Role family 3
Stretch lane
Role family 4
Exploratory lane
| Company | Target title | Updated | Status |
|---|---|---|---|
| summit re | Senior Product Owner | 23.05 · 09:37 | DRAFT |
| alpine fintech | Business Analyst Claims | 23.05 · 18:17 | DRAFT |
| centro cx | Product Owner Digital CX | 23.05 · 09:37 | APPLIED |
| neura consulting | AI Domain Lead | 22.05 · 14:02 | DRAFT |
The problem
The same career has to read differently for each role, Senior PO here, Business Analyst there, CX lead next, a stretch into AI Domain Lead. Tune one cut by hand and the others drift: words shift, numbers move, a gap gets glossed, and one bad sentence in a cover letter sinks the application. And that is before the part that isn't writing at all, tracking what's out, what came back, and which roles are even worth the effort.
The answer wasn't a faster writer. It was a system that treats the CV as data, governs every change against one source of truth, triages roles before they cost effort, and keeps the whole pipeline's status in view.
The approach
A single rule file, twenty-five rules, loads at every session start. No agent can override it. Each agent is scoped to one concern and loads only the playbook and source files it needs. Hooks run between sessions to stamp state, trace sources, and surface drift.
The model runs locally via Claude Code on a Max plan. MCP extends the tool surface, file reads, script calls, renders, all within one session. No API tokens, no external calls, no data leaving the machine.
Facts only. No invention. Ever.
Every claim must trace to a source on disk. If a claim has no source, it does not appear. No exceptions. Ungrounded lines get flagged, the engine ships, but the flag becomes a ticket to resolve before the next run.
Rule 1, loaded every session
Rule constitution
Twenty-five rules load at every session start. No agent can override them. Behavioral rules always on; domain rules activate per agent.
Hook enforcement
Hooks run between sessions, stamping state on commit, scanning for drift on write, promoting stale questions into the ticket tree.
Scoped agents
Each agent loads one playbook and reads only the source files it needs. No agent sees the full system, only its concern.
The pipeline
A role enters and is triaged first, fit, stretch, or skip, before it costs any effort. What's worth it gets a tailored cut of the one master CV, validated against the rules, rendered, and tracked from draft to outcome. The model never invents. It only fills values the schema allows, with content the corpus already contains.
Capture
A pasted job description becomes a versioned markdown file with metadata, role family inference, and the verbatim copy. Every claim downstream traces here.
Triage
A rule-based read of the JD against the positioning matrix. Strong fits go through. Stretches are scored. Wrong-shape roles get marked and don't burn an application slot.
Tailor
The model produces a per-role variant: CV body, cover letter, summary. Strictly inside RULES.md and CV-ENGINE.md. No banned words, no inflated tenure, no claims absent from the source corpus.
Validate
A second pass runs the variant against source-trace, banned-words, page-count, letter-QA, and metric-vs-numbers gates. Anything that fails blocks the render. No soft warnings, no overrides.
Render
Each cut renders ATS-clean: DE/EN, with or without portfolio, with or without cover. Real embedded text, machine-readable section headers, parseable dates. Pdf.js enforces page count + ATS extraction before write.
What comes out
I bring the same loop into product work: hand-write the rules, let the model produce inside them, gate the output.
Let’s talk