Skip to content

Instantly share code, notes, and snippets.

@queso
Created February 11, 2026 18:25
Show Gist options
  • Select an option

  • Save queso/b5a33103e13b0d2b35e5fbdc2101bf8f to your computer and use it in GitHub Desktop.

Select an option

Save queso/b5a33103e13b0d2b35e5fbdc2101bf8f to your computer and use it in GitHub Desktop.
Life OS Examples: Nutrition Preferences & 3D Print Research — markdown files from my Claude Code Brain system (see video: https://youtu.be/iAHwFEbNrok)

3MF File Format Research

Date: January 27, 2026

What's actually inside a Bambu Studio .3mf file and what can we control programmatically. This is the stuff that lets us batch-modify print settings, automate plate naming, and cut waste without touching the GUI.


The Big Picture

A .3mf file is just a ZIP archive. Rename it to .zip, unzip it, and you get a folder structure with XML, JSON, and image files. Everything Bambu Studio knows about your project lives in these files. Which means everything is scriptable.

File Structure

Here's what's inside:

File Format What It Does
Metadata/project_settings.config JSON ALL print settings. The motherload.
Metadata/model_settings.config XML Object definitions, plate assignments, plate names
Metadata/plate_N.json JSON Per-plate layout data (bounding boxes, positions). Only exists for sliced plates.
Metadata/plate_N.png PNG Plate thumbnail images
Metadata/plate_no_light_N.png PNG Thumbnails without lighting
Metadata/top_N.png PNG Top-down view thumbnails
Metadata/pick_N.png PNG Pick thumbnails
Metadata/slice_info.config XML Slicer version info
3D/3dmodel.model XML 3D geometry and build items
3D/Objects/object_N.model XML Individual object geometry files

Programmable Print Settings

Metadata/project_settings.config is where the action is. It's a JSON file with every print setting Bambu Studio exposes. Here are the ones that matter for us:

Flush / Purge Controls

  • flush_multiplier - Currently ['1']. Controls overall purge waste scaling. We proved 0.8 works on Paw Pals heads. Less purge = less waste = faster prints.
  • flush_volumes_matrix - The exact flush volumes between each filament pair. This is the matrix you see in Bambu Studio's flushing dialog. Every color-to-color transition has a specific purge amount.
  • flush_into_infill - Currently 0 (OFF). This is a big one. When enabled, purge waste gets deposited INTO the model's infill instead of building a separate purge tower. Huge potential waste reduction.
  • prime_tower_width - Currently 35. Width of the purge tower.

Infill

  • sparse_infill_density - Currently 13%, tested 11% successfully. Lower = less filament + faster prints.
  • sparse_infill_pattern - Currently gyroid.

Filament Info

  • filament_cost - Array of costs per filament slot. Currently WRONG in our project files. Needs actual prices so the slicer gives us accurate cost estimates.
  • filament_colour - Hex color values for each filament slot.

Plate Names

Plate names live in Metadata/model_settings.config. The structure looks like this:

<plate>
  <metadata key="plater_name" value="MICRO & EARRINGS"/>
  <model_instance>
    <metadata key="object_id" value="2"/>
    <!-- ... -->
  </model_instance>
</plate>

Important gotcha: the XML key is plater_name, not plate_name. Typo in the source code that stuck. Reference: PlateData.plate_name in BambuStudio's bbs_3mf.hpp.

Plate 1 with an empty name shows no label. Named plates get a green text label in Bambu Studio's UI.

Object Identification

Each object carries the name from its original STL file:

<metadata key="name" value="beasty_Pixie_3MF.stl"/>

The chain works like this: Plate → model_instanceobject_id → STL name. You can programmatically figure out what's on each plate.

Example from a real file: Plate 2 "MICRO & EARRINGS" had 44x beasty_Pixie_3MF.stl (micros) and 9x beasty_Pixie_Keychain_3MF.stl (earrings).

Object Scale / Size

Each build item in 3D/3dmodel.model has a transform attribute — a 3x4 affine matrix. The column vector magnitudes give you X/Y/Z scale. So you can programmatically tell how big each object is relative to its original STL.

Example from the Nightbloom Pixie file:

Plate Objects Scale
Plate 1 (unnamed) Pixies + Keychains 100% (full size)
Plate 2 "MICRO & EARRINGS" Pixies + Keychains 54% (micros/earrings)

Same STL on both plates, just scaled differently. The transform matrix tells you exactly what percentage each object is at. This means a script can look at any 3MF and know what size each model is printing at — useful for COGS calculations where the same model prints at different sizes for different product lines (sips vs micros vs earrings).

# Scale extraction from transform matrix
# Transform is 12 floats: row-major 3x4
# sx = sqrt(m[0]² + m[3]² + m[6]²)
# sy = sqrt(m[1]² + m[4]² + m[7]²)
# sz = sqrt(m[2]² + m[5]² + m[8]²)

Plate Grid Coordinate System

Plates are laid out in a 2-column grid. Coordinates are absolute across all plates — not local to each plate. X increases to the right, Y decreases downward.

Grid layout:
  Plate 1 (0,0)    Plate 2 (1,0)
  Plate 3 (0,1)    Plate 4 (1,1)
  Plate 5 (0,2)    Plate 6 (1,2)
  ...

Offset between plates: ~303mm in each direction.

Plate Grid Position X Offset Y Offset
Plate 1 (0,0) 0 0
Plate 2 (1,0) +303 0
Plate 3 (0,1) 0 -303
Plate 4 (1,1) +303 -303

Measured from the Nightbloom Pixie file:

  • Plate 1: X=[39–229], Y=[43–184]
  • Plate 2: X=[342–548], Y=[24–215]
  • Plate 3: X=[244–], Y=[−240–]

When programmatically adding objects to a new plate, you take the coordinates from an existing plate and apply the grid offset. We successfully created Plate 3 "MICRO ONLY" by cloning Plate 2's pixie objects and shifting X by −303 and Y by −303 (moving from grid column 1 back to column 0, and down one row).

What You Need to Add a New Plate

  1. Metadata/model_settings.config: Add new <object> entries (deep copy from source objects) with fresh IDs, plus a new <plate> element with plater_id, plater_name, and <model_instance> children referencing the new object IDs
  2. 3D/3dmodel.model: Add new <object> elements in <resources> (deep copy — must include <components> referencing the mesh sub-objects), plus new <item> entries in <build> with the grid-offset transforms
  3. Re-zip and you're done

The object <resources> entries are critical — each object is component-based, referencing shared mesh sub-objects (e.g., object 20 references components 9–14 for body parts). Deep-copying preserves these references.

Gotcha: different_settings_to_system

This one bit us. When you change a setting in project_settings.config programmatically, Bambu Studio may ignore it unless the setting name is also listed in different_settings_to_system. This is a semicolon-delimited list (per process profile slot) that tells Bambu "these settings override the system profile." Without the entry, Bambu falls back to the profile default and silently discards your value.

Example: We set prime_tower_width from '35' to '20' in the JSON. Bambu ignored it. When the same change was made through the GUI, Bambu added prime_tower_width and prime_tower_rib_width to different_settings_to_system:

"different_settings_to_system": [
    "brim_type;initial_layer_print_height;...;prime_tower_rib_width;prime_tower_width;...",
    ...
]

Rule: Any programmatic setting change must also be registered in different_settings_to_system. The array slots map like this:

different_settings_to_system: [
    "[0] process profile overrides",
    "[1] filament slot 1 overrides",
    "[2] filament slot 2 overrides",
    "[3] filament slot 3 overrides",
    "[4] filament slot 4 overrides",
    "[5] ???"
]

For process settings (prime tower width, infill, etc): add the setting name to slot [0]. For filament settings (prime volume, cost, etc): add the setting name to slots [1] through [4] (one per filament).

Entries are semicolon-separated and alphabetical. Example for filament prime volume on all 4 slots:

"different_settings_to_system": [
    "brim_type;...;prime_tower_width;...",
    "filament_prime_volume;supertack_plate_temp;...",
    "filament_prime_volume;supertack_plate_temp;...",
    "filament_prime_volume",
    "filament_prime_volume",
    ""
]

Other Gotchas

  • All values are strings. '35' not 35. Wrong type = silently ignored.
  • Wipe tower positions are per-plate. wipe_tower_x and wipe_tower_y are arrays — one entry per plate. Adding a plate means adding a position entry.
  • Filament prime volume rule of thumb: Set filament_prime_volume to prime tower width + 5mm. So width 20 → prime volume 25 mm³.
  • Filament config files use inheritance. Metadata/filament_settings_N.config only stores overrides from the parent profile (inherits key). If a setting isn't listed, it uses the parent's default. But for programmatic changes, you don't need to touch these files — just set the value in project_settings.config and register it in different_settings_to_system. Bambu reads the project-level array.
  • Filament config file numbering ≠ slot numbering. There may be only 2 filament config files for 4 slots. The mapping isn't straightforward. Stick to project_settings.config arrays for programmatic changes.

Filament Settings

Per-filament settings are arrays in project_settings.config, indexed by filament slot:

Setting Description Current Values
filament_prime_volume Purge on filament change (mm³) ['25','25','25','25']
filament_prime_volume_nc Purge on hotend change (mm³) ['60','60','60','60']
filament_cost Price per kg ['24.52','24.52','29.99','24.15']
filament_colour Hex colors ['#D1B2EC','#443089','#A03CF7','#FFFFFF']
filament_cooling_before_tower Cool before tower ['0','0','0','0']
filament_minimal_purge_on_wipe_tower Min purge (mm) ['15','15','15','15']

Per-filament config files also exist at Metadata/filament_settings_N.config but these use inheritance and only store overrides. For batch scripting, the project_settings.config arrays + different_settings_to_system registration is the reliable path.

Scripts & Tools

  • sip-hole-resizer-script-spec.md — Script spec for automatically finding sip-hole models in a 3MF and creating a new plate with resized copies (different sip sizes) while keeping the hole at exactly 10.2x10.2x55mm. Builds on the negative volume detection, selective scaling math, and joint awareness documented below.

What We Should Build

  1. Turn on flush_into_infill and test the impact on waste. This could be the single biggest waste reduction lever we haven't pulled yet.
  2. Fix filament_cost values in all project files. Without accurate costs, the slicer's estimates are useless.
  3. Test lower flush_multiplier values - try 0.75 and 0.7 on more products beyond Paw Pals heads.
  4. Batch modification script - Unzip 3MF, modify project_settings.config, rezip. Apply settings changes across dozens of project files at once.
  5. Auto-name plates - Read the object IDs on each plate, map to STL names, generate a descriptive plate name automatically.

The Workflow for Modifying a 3MF

1. Copy the .3mf file
2. Unzip it (it's just a ZIP)
3. Edit the JSON/XML files you need
4. Re-zip with the same structure
5. Rename back to .3mf
6. Open in Bambu Studio to verify

That's it. No special tools needed beyond a script that handles zip/unzip and JSON/XML parsing.

Negative Volumes (Boolean Subtraction Holes)

Date: February 10, 2026

Discovered while inspecting the BeastyPixie DarkMagic 3MF. Some models on Plate 1 have cylindrical holes cut into them (for magnets/pins), others don't. The difference is visible in the XML.

How Negative Volumes Work in 3MF

In 3D/3dmodel.model, each top-level object has <components> that reference sub-objects from shared mesh files. The sub-objects have a type attribute:

  • type="model" — Normal additive geometry (the body, wings, eyes, etc.)
  • type="other"Negative volume. BambuStudio subtracts this mesh from the model via boolean difference. This is how holes are cut.

Example from object_130.model:

<!-- Normal body part -->
<object id="8" type="model">
  <mesh>...</mesh>
</object>

<!-- Negative cylinder (cuts a hole) -->
<object id="14" type="other">
  <mesh>
    <vertices>
      <vertex x="0" y="0" z="-12.8"/>
      <vertex x="0" y="0" z="12.8"/>
      <vertex x="0" y="12.8" z="-12.8"/>
      <!-- ... circle of vertices at z=-12.8 and z=+12.8 -->
    </vertices>
  </mesh>
</object>

The cylinder mesh is defined at a base size of radius=12.8mm, height=25.6mm (z +/-12.8). It gets scaled by the component transform to the actual hole dimensions.

Cylinder Sizing via Component Transform

The component transform for the cylinder (objectid 14) within an assembly:

<component objectid="14"
  transform="0.398437494 0 0 0 0.398437494 0 0 0 2.14843747 0.0337081218 -11.4074222 -0.297823911"/>

Breaking down the 3x4 affine matrix (m00 m01 m02 m10 m11 m12 m20 m21 m22 tx ty tz):

Axis Scale factor Mesh base Result
X 0.398437494 12.8mm radius × 2 10.2mm width
Y 0.398437494 12.8mm radius × 2 10.2mm length
Z 2.14843747 12.8mm half-height × 2 55.0mm height

Translation (0.03, -11.4, -0.3) positions the cylinder relative to the assembly origin, so it punches through the model with some sticking out below the build plate.

Identifying Which Models Have Holes

Two shared mesh files on the BeastyPixie:

  • object_104.model — 6 sub-objects (ids 1-6), all type="model". No hole.
  • object_130.model — 7 sub-objects (ids 8-14), where id 14 is type="other". Has hole.

Some assemblies reference object_130 but only include 6 of its 7 sub-objects (ids 8-13, skipping 14). These also have no hole — the negative volume is simply not included in their component list.

So the pattern is: if an assembly's <components> list includes objectid 14, it has the cylinder hole. If it stops at objectid 13, it doesn't.

Plate 1 of DarkMagic BeastyPixie:

Object IDs Mesh source Components Has hole?
7, 16, 18, 20, 22 object_104 6 (ids 1-6) No
76, 77, 78 object_104 6 (ids 1-6) No
36 object_130 6 (ids 8-13) No
26, 28, 32, 34, 79 object_130 7 (ids 8-14) Yes

Plate Assignment (Important Gotcha)

Object IDs do NOT map sequentially to plates. Odd/even IDs can land on different plates. The authoritative plate assignment is in Metadata/model_settings.config:

<plate>
  <metadata key="plater_id" value="1"/>
  <model_instance>
    <metadata key="object_id" value="7"/>
    <metadata key="instance_id" value="0"/>
  </model_instance>
  <!-- more model_instances... -->
</plate>

The build item X/Y coordinates in 3dmodel.model use the plate grid coordinate system (see above), but model_settings.config is the definitive source for "which object is on which plate."

Selective Scaling: Shrink Model, Keep Hole Same Size

Date: February 10, 2026

Problem: You want to shrink a figurine by 10% but keep the magnet/pin hole the same diameter so the same hardware fits.

Solution: Scale the build item transform by 0.9 (everything shrinks), then counter-scale the cylinder component transform by 1/0.9 (cylinder grows back to original size). The two scales cancel for the cylinder: (1/0.9) × 0.9 = 1.0.

The Math

The transform pipeline for a vertex v in component c of build item b:

v_final = v × M_component × M_build

Where each M is a 3x4 affine matrix (3x3 rotation/scale + translation).

Step 1: Scale the build item's 3x3 by 0.9

Original build transform for object 26:

-6.123234e-17  1  0  -1  -6.123234e-17  0  0  0  1  127.985  80.435  13.098

This is a 90-degree Z rotation + translation. Multiply the 3x3 portion by 0.9:

-5.5109106e-17  0.9  0  -0.9  -5.5109106e-17  0  0  0  0.9  127.985  80.435  13.098

Translation stays the same — model stays in the same spot on the plate, just shrinks around that point.

Step 2: Counter-scale the cylinder component's 3x3 by 1/0.9

Original cylinder component transform:

0.398437494  0  0  0  0.398437494  0  0  0  2.14843747  0.034  -11.407  -0.298

Divide the 3x3 by 0.9:

0.442708327  0  0  0  0.442708327  0  0  0  2.387152744  0.034  -11.407  -0.298

Translation stays the same — the hole's position relative to the assembly origin doesn't change. Since the build transform scales positions proportionally, the hole ends up in the correct relative spot on the shrunken model.

Result per component:

Component Build 3x3 Component 3x3 Net effect
Body parts × 0.9 × 1.0 (untouched) Shrinks 10%
Cylinder hole × 0.9 × 1/0.9 = 1.111 Stays original size

Worked Example

Applied to object 26 (Plate 1, BeastyPixie DarkMagic). Two edits to 3D/3dmodel.model:

  1. Build item (line 1234): scale 3x3 by 0.9
  2. Cylinder component within object 26's definition (line 156): scale 3x3 by 1/0.9

Output: A1-BeastyPixie-DarkMagic-RedTwinkle-BlackTwinkle-White-90pct-test.3mf

After opening in Bambu Studio, the model may float slightly above the build plate (Z origin shifted from scaling). Use "Drop to build plate" to fix.

Generalizing This

For any scale factor S:

  • Build item 3x3: multiply by S
  • Cylinder component 3x3: multiply by 1/S
  • All translations: leave untouched

This works for any component you want to "lock" at a fixed size while the rest of the model scales. Could also apply to screw holes, snap-fit connectors, or any mechanical interface that needs to stay at a specific dimension.

Finding Articulated Joints in Mesh Data

Date: February 10, 2026

Our models are articulated (print-in-place ball joints). When placing negative volume holes (sip holes, magnet holes), we need to know where the joints are so we don't cut through them and break articulation. The joint locations change from model to model, but the technique for finding them is the same.

The Principle

Each articulated model is an assembly of multiple sub-objects (body, head, wings, legs, etc.) positioned by component transforms. Where two components' bounding boxes overlap in world space, there's a joint. The overlap region is the danger zone for hole placement.

Step 1: Identify the Components

Each assembly's <components> list in 3dmodel.model tells you which mesh sub-objects make up the model and where they sit. The component transform translations position each part relative to the assembly origin:

<object id="26">
  <components>
    <component objectid="8"  transform="1 0 0 0 1 0 0 0 1  0.0   -15.08  -1.31"/>  <!-- body -->
    <component objectid="9"  transform="1 0 0 0 1 0 0 0 1 -14.50  -11.50  -8.59"/>  <!-- left wing -->
    <component objectid="10" transform="1 0 0 0 1 0 0 0 1  14.50  -11.50  -8.59"/>  <!-- right wing -->
    <component objectid="11" transform="1 0 0 0 1 0 0 0 1  -9.96    6.38   4.87"/>  <!-- left leg -->
    <component objectid="12" transform="1 0 0 0 1 0 0 0 1   9.96    6.38   4.88"/>  <!-- right leg -->
    <component objectid="13" transform="1 0 0 0 1 0 0 0 1   0.0    14.99   0.0"/>   <!-- head -->
    <component objectid="14" transform="0.398 0 0 0 0.398 0 0 0 2.148 0.03 -11.41 -0.30"/>  <!-- neg cylinder -->
  </components>
</object>

Symmetric translations (±14.5, ±9.96) are mirrored left/right pairs. A component at the origin-ish is the central body. The component furthest in one direction is the head/tail.

Step 2: Get Each Component's Bounding Box

Parse the vertex data from the shared mesh file (e.g., object_130.model). For each sub-object, find min/max X, Y, Z:

import re

with open('object_130.model', 'r') as f:
    content = f.read()

for obj_id in [8, 9, 10, 11, 12, 13]:
    match = re.search(rf'<object id="{obj_id}".*?</object>', content, re.DOTALL)
    verts = re.findall(r'vertex x="([^"]+)" y="([^"]+)" z="([^"]+)"', match.group())
    xs = [float(v[0]) for v in verts]
    ys = [float(v[1]) for v in verts]
    zs = [float(v[2]) for v in verts]
    print(f"ID {obj_id}: X[{min(xs):.1f}, {max(xs):.1f}] "
          f"Y[{min(ys):.1f}, {max(ys):.1f}] Z[{min(zs):.1f}, {max(zs):.1f}]")

Step 3: Compute World Bounding Boxes

Add each component's translation offset to its local bounding box:

world_min = local_min + translation
world_max = local_max + translation

For components with identity rotation (scale=1 in the 3x3), this is a straight addition. If the component has rotation or non-uniform scale in its 3x3, you need to transform the bounding box corners properly.

Step 4: Find Overlaps Between Component Pairs

Two components share a joint where their world bounding boxes overlap in all three axes:

def overlap(a_min, a_max, b_min, b_max):
    o_min = max(a_min, b_min)
    o_max = min(a_max, b_max)
    return (o_min, o_max) if o_min < o_max else None

# For each pair of components, check X, Y, Z overlap
# If all three axes overlap, there's a joint in that region

The overlap center is the approximate joint center. The overlap extent tells you how big the danger zone is.

What It Looks Like in Practice

Hints that help identify which component is which, without needing to visually inspect:

  • Vertex count correlates with part complexity. The body and head have 30k+ vertices. Wings have ~4.5k. Legs have ~2k.
  • Mirrored translations (same magnitude, opposite X sign) are left/right pairs — wings, legs, ears, etc.
  • Component near the assembly origin (small translation) is usually the central body.
  • Largest bounding box is usually the body or head.
  • Smallest bounding box with small vertex count is an extremity (leg, tail, ear).

Interpreting the Overlaps

Not every bounding-box overlap is a ball joint — bounding boxes are coarse. But for articulated print-in-place models:

  • Large overlaps (~8-24mm) at the center → main ball joint (head-body). This is the big circular socket visible from the bottom.
  • Medium overlaps (~9-10mm) at symmetric X offsets → wing/arm joints.
  • Small overlaps (~1.5-7mm) → leg/extremity joints. These are tighter fits and more fragile.
  • No overlap between non-adjacent parts (e.g., head ↔ wings) → no joint, as expected.

Safe Zone for Hole Placement

The negative cylinder hole should go in the body, away from all joint overlap zones. General rules:

  1. Stay in the central body component's bounding box
  2. Avoid any region where another component's bounding box overlaps
  3. The current BeastyPixie placement (Y≈-11.4 in assembly space) sits between the wing joints and well away from the head joint and legs — a good example of surgical placement
  4. When in doubt, bias toward the "back" of the model (away from the head joint, which tends to be the largest and most visible)

Nutrition Preferences

Rules and preferences for food suggestions. Claude: read this before suggesting meals.

Hard Rules

Never Suggest

  • "Chicken breast + veggies" or any variation of bland fitness bro food
  • Plain/boring meals with no flavor
  • DoorDash or delivery (trying to break this habit)
  • Salmon (hate it)
  • Bell peppers (family hates them)
  • Onion or green onion (Wendy's allergy) - use shallots instead
  • High niacin foods - triggers gout (fortified cereals, excessive chicken breast)
  • Pepperoncini or giardiniera (family won't eat)

Always Remember

  • Calories are king - deficit matters most (CICO)
  • Protein is the priority macro for muscle preservation
  • Fat going over is fine if calories and protein are on target
  • Comfort food is fine if it fits macros

Health Constraints

Gout (Josh)

  • Avoid high niacin foods: fortified cereals, too much chicken breast
  • Monitor purine intake when flaring

Onion Allergy (Wendy)

  • NO onion (any kind) or green onion
  • Shallots are OK
  • Must sub shallots for onion in all recipes

Food Preferences

Proteins I Like

  • Beef (steaks, ground beef)
  • Pork (tenderloin, chops)
  • Eggs
  • White fish (sea bass, etc.) - NO salmon
  • Chicken: ALWAYS 50% breast / 50% thighs split (not just breast)
  • Deli meats: ham, chicken, roast beef

Snacks I Like

  • Pretzel crisps
  • Alpha Bites brownies
  • Cottage cheese cookie dough
  • Protein shakes (Premier Protein, Fairlife)

Bread/Wraps

  • Low carb tortillas (preferred)
  • Low carb bread (preferred)
  • Regular bread/tortillas ok if macros fit

Cuisines I Like

  • Mexican (tacos, carnitas, enchiladas)
  • Italian (pasta, meatballs)
  • Asian (stir fry, teriyaki)
  • American comfort (pot roast, casseroles, mac and cheese)
  • BBQ/Smoked meats

Sauces & Flavors

  • Buffalo/hot sauce
  • Ranch
  • BBQ sauce
  • Cheese-based (queso, cheddar sauces)

Cooking & Equipment

Kitchen Gear

  • Lello Musso ice cream maker
  • KitchenAid stand mixer (for shredding meat)
  • Crockpot
  • Smoker
  • Air fryer
  • Breville counter oven
  • Gas stove and gas oven
  • Large upright deep freeze

Cooking Style

  • Crockpot dumps (morning prep, dinner ready)
  • Freezer casseroles (prep Sunday, easy weeknight)
  • Batch cooking for family (6 servings typical)
  • Smoking meats on weekends

Meal Constraints

Lunch

  • Needs to be easy (working from home but busy)
  • Leftovers are ideal
  • Sandwiches work great: ham, chicken, or roast beef on low carb bread
  • Protein shakes/bars work in a pinch

Dinner

  • Family meals - needs to be kid-friendly
  • Light spice ok, nothing too hot
  • NO bell peppers
  • See crockpot meals and freezer meals for rotation

Fast Food (In a Pinch)

  • Chick-fil-A (grilled nuggets, etc.)
  • Chipotle (bowls)
  • Subway/deli sandwiches

Drinks

  • Coffee/espresso (daily)
  • Protein shakes (Premier Protein, Fairlife)
  • Diet soda/zero sugar drinks
  • Water/sparkling water
  • Alcohol (occasional)

Low Appetite Days (Retatrutide)

  • Prioritize liquid protein (shakes)
  • Protein ice cream counts as a meal
  • Don't force solid food - hit protein target however possible

Notes

  • Add preferences here as we discover them
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment