My job-search tool had five functions whose only purpose was fixing JSON that Claude had just written. _clean_json_text, _fix_unescaped_newlines, _fix_single_quotes, _strip_markdown_wrapper, _extract_and_parse_json. There was also a sixth, _retry_json_fix, which took the broken JSON and sent it back to the model with a polite request to fix its own mess. I wrote every one of them, one bug at a time, over weeks. I was a little proud of them.

That was the problem.

How you end up with five parsers

JobSearch is my personal tool, in production, single user: me. It ingests job offers from nine boards, and when I press "Analyze", Claude reads the offer against my CV and returns a structured verdict: score, recommendation, career track, the English level the ad actually requires. That verdict has to be JSON, because everything downstream is a database row, not prose.

The first version did what every tutorial does. Ask the model for JSON in the prompt, take response.content[0].text, run json.loads on it. It worked in the demo and then production started teaching me things.