I Refactored My Marriage to Emit Exactly One JSON Line on Stdout

For seven years, my wife and I have communicated like animals. She would say something. I would say something back. Sometimes I would respond with a follow-up question. Sometimes she would clarify. Sometimes neither of us was sure whether the conversation had ended or simply paused. There were no exit codes. There was no contract. We were emitting an unbounded stream of natural language and then trying to parse each other's vibes.

I am a software engineer. I have known for thirty years that this was wrong. Last Tuesday, I fixed it.

Effective 09:14 last Tuesday, my marriage emits exactly one JSON line on stdout per day. The line conforms to a schema. The schema lives in a Git repository. My wife has not been added as a contributor yet because I am still finalizing the access policy.

The schema

{"status":"ok","mood":"neutral","needs":["pickup_dry_cleaning"],"capacity_hours":2.5}

The status field is ok or error. Not "fine." Not "tired but okay." Not "I don't really want to talk about it right now." ok or error. We are no longer in the business of emitting feelings as prose.

The mood field is one of an enum: neutral, pleased, concerned, escalated. There is a backlog ticket to add playful. It is unlikely to ship.

The needs array is the only field that takes free-form input, and only because I have not yet had time to enumerate every domestic action into a controlled vocabulary. This is on the roadmap for Q3.

capacity_hours is a float. It represents how much remaining bandwidth a given party has to do household labor that day. It is the most useful field. It is also the field my wife has refused to populate, on grounds that "you can't measure that," which is, regrettably, not a valid error response under the protocol.

What goes on stderr

Everything else.

If my wife wants to tell me about her day, that is a log message. It goes to stderr. I am happy to read stderr. I do read stderr. I am not parsing stderr. Stderr is for humans. Stdout is the contract.

If she wants to express that she is annoyed with me, also stderr. I will absolutely read it. I will not act on it unless it shows up in the next morning's JSON line as "status":"error","reason":"trash_not_taken_out".

This has, predictably, caused friction.

Initial results

Day one of the new protocol was excellent. I knew, with structural certainty, that my wife was at capacity 6.0 and that the only need was groceries. I bought groceries. I returned. The day terminated cleanly with a zero exit code.

Day two she did not emit a JSON line. I treated this as a timeout and assumed sensible defaults.

Day three she emitted what appeared to be a JSON line but contained, in the mood field, the value "are you serious right now". This is not in the enum. The protocol crashed. I logged the schema violation and escalated.

Day four she emitted a single line that read {"status":"error","message":"sleep on the couch"}. I parsed it correctly. The protocol worked.

What I am taking forward

I will be honest: the rollout has not been frictionless. There has been pushback. There have been what one might generously call "scope discussions." My mother-in-law has been looped in, against my objections, as a stakeholder. I am being asked to justify the protocol in writing to people who do not write code.

But the marriage is in a known state. I know what state it is in. Every previous week of the marriage, I did not know what state it was in. I had vibes. The vibes lied. The structured output does not lie. When my wife emits {"status":"error","reason":"you forgot our anniversary"}, I can parse that. I can act on it. I can route it to the appropriate handler. The handler is currently a draft. The handler will be ready by the time the next anniversary fires.

My wife is now drafting an RFC that would amend the protocol to include a feelings array of arbitrary length, with no schema on the contents, that I would be required to read every morning before saying anything to anyone. I have asked her to file an issue. She has asked me to come to bed. I have asked her to put that on stdout. We are negotiating, in writing, on the kitchen whiteboard, in YAML.

It is going well.