← Back to writing

2026-04-05 · 7 min read

Tracking a Cut With Claude Code

I'm on a cut and my nutritionist is a markdown file.

I wrote a 400-line skill file that tells Claude Code how to track my food, compute my macros, and tell me exactly what to eat for dinner so I hit my targets. I type /track in my terminal. "log 220g thigh, 140g rice." "what's left." "adjust today." It reads my food log, does the math, responds in one line.

The thing I need most from a tracker is the conversation after logging.


The problem that matters

Every calorie tracker solves the easy problem: recording what you ate. The hard problem is 6pm. You've been eating roughly on plan all day, but things drifted. A little more rice at lunch. Skipped the egg because the store was out. Now you've got four macros to hit and all of them need to land within 90-110% of target for the day to count. You could open a spreadsheet and do subtraction on four columns, or you could type:

"adjust today"

And get back:

"Eat saba 160g, rice 180g, peanut butter 15g. End of day: HIT."

I built this to outsource the part where you stare at four macros trying to figure out what combination of chicken, rice, and peanut butter lands all of them.


This isn't prompt engineering

The first thing people assume is that I told Claude "be my nutritionist" and it works great.

If you give an LLM creative freedom over meal suggestions, you get a different answer every time. I tried it. Early versions would suggest salmon (not in my rotation), recommend "adding some healthy fats like avocado" (I don't want to eat avocado), or give different advice for identical inputs depending on where we were in the conversation. Sometimes it would prioritize calories and underfill protein. Other times it would suggest three foods when one would do. Completely unreliable.

The skill file doesn't ask Claude to be smart about nutrition. It gives Claude a specific set of steps to follow and a constrained set of foods to pick from.


The algorithm (written in English)

At the core of the skill is an adjustment algorithm, but it's not code. It's a set of steps written in plain English that Claude reads and follows. When I ask "what should I eat," the skill file tells it:

  1. Compute remaining macros from today's logs vs targets
  2. Pick a protein source to fill the protein deficit
  3. Check if fat is projected under 90%. If yes, add a fat source. This step is mandatory and fires before anything else because fat is the macro that chronically comes up short on a cut. Claude will optimize around it every time if you don't force the check
  4. Fill remaining carbs with rice, calculated to exact grams (remaining_carbs / 0.356)
  5. Verify all four macros land in the hit zone. If they can't, say which one fails and by how much

The food pool is locked to a 29-item database. 10 of those items make up 95% of what I eat. Each food has a fixed role: chicken thigh and saba are protein sources, peanut butter and milk are fat sources, rice is the carb filler. These roles are specified in the skill file as a table.

This isn't truly deterministic. There's no runtime enforcing the steps. Claude reads the instructions, interprets them, and could theoretically deviate. But the problem space is small enough (29 foods, 4 macros, fixed roles) and the instructions specific enough that it produces the same output for the same inputs. Not because it's guaranteed to, but because there's only one reasonable interpretation when the constraints are this tight.


Why use Claude at all

A script can do arithmetic. But a script needs structured input. track log --food chicken_thigh --grams 220 --food rice --grams 140 is miserable to type every meal. That kind of interface is why people stop tracking after a week.

Claude does everything. It parses "220g thigh, 140g rice, broc" into food matches with gram amounts, reads the JSON files, computes the remaining macros, picks the foods, calculates exact grams of rice. There's no separate engine. The entire system is Claude reading instructions and following them.

What the skill file does is constrain the decisions. Without it, Claude parses your input just fine but then suggests foods you don't buy and gives you different advice every time. With it, Claude still does all the work, but the decision space is narrow enough that the output is predictable. The skill file doesn't replace Claude's reasoning. It boxes it in.


Trust hierarchy

The skill defines what beats what when information conflicts. Logs (what I actually ate) beat limits (my targets) beat meal plans (what I intended to eat) beat the food library beat whatever I say in conversation.

Claude is agreeable by default. If I say "I think chicken thigh is 200 calories" mid-conversation, it'll go with it. My skill file says check the JSON instead. The data is the authority, not the chat.

I only added this after getting burned. Got a wildly wrong "remaining" calculation because Claude used a number I'd mentioned casually instead of reading the data file. One line in the skill file fixed it permanently.


Why English and not TypeScript

I tried coding the adjustment logic first. It worked, but every time I changed my mind (dropped olive oil, stopped buying oatmeal, added a new treat to fit in) I had to refactor a function, handle edge cases, re-test.

The skill file is English. "Never suggest olive oil. Thigh + eggs + PB + milk cover fat needs." I wrote that line after deciding olive oil wasn't worth measuring 3g on a spoon. Took 10 seconds. The equivalent code change would touch the allowed foods list, the fat-source priority array, and at least one test.

The tradeoff is that Claude interprets the rules, and early on it interpreted them loosely. So the file got more specific over time. "MUST only use foods from foods.json" replaced "prefer foods from foods.json." "This step is mandatory. Do NOT skip" replaced "do this if needed." You learn to write it like a contract, not a suggestion. 400 lines of increasingly specific English, and it works reliably.

I used a language model so I could write structured logic in natural language instead of a programming language. The model interprets the rules instead of executing them, which means it can technically get it wrong. In practice it doesn't, because there's not much room to improvise when the food list has 29 items and every step says "mandatory."

If I wanted actual guarantees, I could make the core logic deterministic. The adjustment algorithm is just arithmetic on a lookup table. Write it as a function, have Claude parse the natural language input into structured data, call the function, format the output. Claude as NLU in, formatter out, deterministic function in the middle. That would make the split between "Claude's job" and "not Claude's job" real instead of approximate. I haven't needed to because the constraints are tight enough, but that's where this goes if it ever breaks.


Where it is now

I've logged every meal since the cut started. I hit my macros most days. When I miss, I know exactly which number was off and why. The skill file keeps getting better because every time Claude does something I didn't want, I add a line.