Disclaimer
This is not medical advice.
I’m a software developer and father, not a physician or nutritionist. My son requires a special ketogenic diet, and to better understand it, I decided to follow a keto diet myself. This book is simply where I write down what I learn along the way.
These are personal notes for myself. They are not a meal plan for you. The information here could very well be incorrect, outdated, or misunderstood on my part.
If you’re considering a ketogenic diet, please consult a qualified healthcare professional. Everyone’s body and nutritional needs are different.
Use this at your own risk.
The Middle Ground Diet
Macro Breakdown
Daily target macronutrient breakdown for the ketogenic diet.
This is a 1,600 kcal ketogenic diet designed as a “middle ground” that works for different people with different goals: rapid fat loss, slow and steady weight reduction, or maintenance with body recomposition. It’s not perfectly optimized for any single group, but it’s an acceptable baseline that allows multiple people to follow the same meal plan. Your results will vary based on your starting point, activity level, and metabolism. See the Personas section for specifics.
The daily calories are divided into three buckets: a large lunch, a small snack, and a moderate dinner. Breakfast is skipped entirely. This structure combines the benefits of intermittent fasting (extended overnight fast until noon) with practical meal timing: larger portions when energy is needed most, lighter eating as the day winds down.
| Nutrient | Weight (Grams) | Kcal | Percentage of Total Kcal |
|---|---|---|---|
| Total | - | ~1,600 | 100% |
| Protein | 125g | 500 | ~31% |
| Net Carbs | 25g | 100 | ~6% |
| Fats | 111g | 999 | ~63% |
Note: Protein and carbs provide ~4 kcal per gram, while fats provide ~9 kcal per gram.
What are net carbs? Net carbs = total carbs − fiber. Fiber is subtracted because it isn’t digested and doesn’t raise blood sugar or insulin levels. This is what matters for staying in ketosis.
Personas
This 1,600 kcal plan balances two different biological needs using the same fuel. Here’s how the macro profile (125g protein, 25g net carbs, 111g fat) fits different personas.
| Feature | 70kg Male, Moderate Deficit, Fat Loss and Muscle Retention | 80kg Female, Postpartum, Gentle Deficit, Sustainable Fat Loss |
|---|---|---|
| Profile | Male, 70kg | Female, 82kg, Postpartum |
| Current State | Average | High BMI, hormonally sensitive |
| Goal | Reach 65kg / Maintain Muscle | Slow, steady weight loss |
| Role of 1,600 kcal | Deficit: ~400 kcal/day | Deficit: ~250-300 kcal/day |
| Pace | Moderate/Fast | Slow/Sustainable |
70kg Male, Moderate Deficit, Fat Loss and Muscle Retention
Why this works: At a healthy weight, the body wants to burn muscle instead of fat if not given a reason to keep the muscle. The 125g of protein acts as “insurance.” It tells the body: “We have plenty of building blocks, so go ahead and burn that belly fat for energy instead.”
Be careful with: Overtraining. Working out 45 minutes every day on 1,600 kcal can lead to a “crash.” Feeling dizzy or significant strength drops may indicate a need for 1-2 extra spoons of fat (olive oil/butter) to keep calories from dropping too low.
The result: Reaching target weight looking “toned” rather than just “skinny.”
80kg Female, Postpartum, Gentle Deficit, Sustainable Fat Loss
Why this works: After pregnancy, the body has been through a metabolic marathon. A massive calorie deficit would spike cortisol (stress hormone) and cause weight retention. 1,600 kcal is a “gentle” deficit, providing enough energy to manage daily life without “hangry” mood swings.
Be careful with: Hidden carbs. Since the deficit is smaller (~250 kcal), a few extra bites of fruit or snacks can completely erase daily weight-loss progress.
The result: Consistent loss of ~0.5kg per week and stable energy.
Why This Diet Works for Both
- Protein sparing: By keeping protein at ~30%, no one is “starving” their organs or muscles.
- Anti-inflammatory: Removing sugar and processed carbs helps with recovery and joint health.
- Satiety: Fat and protein take longer to digest. Unlike a 1,600 kcal “low fat” diet, hunger doesn’t return two hours after eating.
The Transition Period
Regardless of persona, the first 10 to 14 days are the hardest. The brain is switching from burning glucose (sugar) to burning ketones (fat).
Symptoms may include:
- Temporary drop in workout performance
- Afternoon “brain fog”
The fix: Don’t eat more carbs. Instead, increase salt intake. Drink a cup of salty bone broth or add an extra pinch of sea salt to lunch.
The Three-Bucket Approach
This approach is ideal for a busy household. By skipping breakfast, calories are consolidated into three windows, allowing for larger, more satisfying portions that make the 1,600 kcal limit feel much more substantial.
Daily Bucket Split
| Meal | Time | Kcal | Protein | Fat | Net Carbs |
|---|---|---|---|---|---|
| Lunch (The Big Meal) | 12:00 | ~750 | 60g | 52g | 10g |
| Snack (Small & Easy) | 15:00 | ~300 | 15g | 23g | 8g |
| Dinner (The Lighter Meal) | 18:00 | ~550 | 50g | 36g | 7g |
| TOTAL | 1,600 | 125g | 111g | 25g |
Bucket 1: The “Power Lunch” (12:00)
Target: ~750 kcal · 60g protein · 52g fat · 10g net carbs
This is the primary fuel. Since breakfast is skipped, this meal needs to be high in protein to keep you satiated until the evening.
The Goal: A large portion of hot protein (meat or fish) and a high-volume side of green vegetables cooked in healthy fats (butter or oil).
The Logic: Getting nearly 50% of daily protein here ensures muscles have building blocks throughout the afternoon.
Bucket 2: The “Bridge Snack” (15:00)
Target: ~300 kcal · 15g protein · 23g fat · 8g net carbs
This is a small, low-effort window designed to stop you from reaching for unhealthy snacks.
The Goal: A mix of fat and fiber.
The Logic: A significant portion of daily carbs is allocated here (8g), as keto-friendly snacks like yogurt, berries, or nuts are naturally higher in carbs than pure meat or eggs.
Bucket 3: The “Easy Dinner” (18:00)
Target: ~550 kcal · 50g protein · 36g fat · 7g net carbs
A lighter, often cold or quick-prep meal. This is when the house is usually most chaotic, so cooking complexity stays low.
The Goal: High protein but lower “bulk” than lunch. Think eggs, cold cuts (Jamón), or cheese.
The Logic: Keeping this meal moderate in calories ensures you aren’t going to bed with a heavily laboring digestive system, but the 50g of protein ensures your body doesn’t enter a catabolic (muscle-burning) state overnight.
mdBook Rust Integration
This book uses mdBook’s Rust code execution to provide interactive nutritional calculators.
How It Works
Each recipe includes an editable Rust program that calculates the total nutritional values based on the ingredients. You can:
- Modify ingredient values if your specific products have different nutritional content (e.g., your yogurt brand has different protein/fat ratios)
- Adjust portion sizes to match what you actually use
- Change target values if your meal targets differ from the defaults
- Run the program to see if your modified recipe still hits the nutritional targets
This lets you quickly verify that substitutions or portion adjustments still fit within your macro goals without manual calculation.
Usage
- Look for the code block in a recipe
- Edit any values (ingredients, amounts, targets)
- Click “Run” to see the calculated totals and whether they match your targets
Lunch
Target: ~750 kcal · 60g protein · 52g fat · 10g net carbs
This is the primary fuel. Since breakfast is skipped, this meal needs to be high in protein to keep you satiated until the evening.
The Goal: A large portion of hot protein (meat or fish) and a high-volume side of green vegetables cooked in healthy fats (butter or oil).
The Logic: Getting nearly 50% of daily protein here ensures muscles have building blocks throughout the afternoon.
Example lunch
Snacks
Target: ~300 kcal · 15g protein · 23g fat · 8g net carbs
This is a small, low-effort window designed to stop you from reaching for unhealthy snacks.
The Goal: A mix of fat and fiber.
The Logic: A significant portion of daily carbs is allocated here (8g), as keto-friendly snacks like yogurt, berries, or nuts are naturally higher in carbs than pure meat or eggs.
Quick Greek Yogurt with Walnuts and Raspberries
A fast, no-cook ketogenic snack designed for maximum efficiency. This bowl balances the high-protein content of Greek yogurt with the dense healthy fats of walnuts to provide sustained energy until dinner.
Ingredients (Per Serving)
- 150g Full-fat Greek Yogurt (5% fat, plain/unsweetened) - about 2/3 cup
- 21g Walnut halves - about 7 halves, or a small handful
- 25g Fresh Raspberries - about 8-10 berries
Preparation Steps
Mix joghurt, walnut, and raspberries.
Nutritional Values (per 100g)
Reference values from nutrition labels:
| Ingredient | Kcal | Protein | Fat | Net Carbs |
|---|---|---|---|---|
| Greek Yogurt (5%) | 93 | 8.7g | 5.0g | 3.3g |
| Walnuts | 665 | 15.0g | 65.0g | 5.0g |
| Raspberries | 27 | 1.25g | 0.25g | 5.0g |
Recipe Breakdown (actual amounts)
| Ingredient | Amount | Kcal | Protein | Fat | Net Carbs |
|---|---|---|---|---|---|
| Greek Yogurt (5%) | 150g | 140 | 13.0g | 7.5g | 5.0g |
| Walnuts | 21g | 140 | 3.2g | 13.7g | 1.1g |
| Raspberries | 25g | 7 | 0.3g | 0.1g | 1.3g |
| TOTAL | 286 | 16.5g | 21.2g | 7.3g | |
| Target | 300 | 15.0g | 23.0g | 8.0g | |
| Diff | -14 | +1.5g | -1.8g | -0.7g | |
| Diff % | -5% | +10% | -8% | -9% |
Interactive Calculator
Modify the values below if your ingredients have different nutritional content, then run to check if the meal still hits your targets. See mdBook Rust Integration for details.
// Kcal per gram of each macronutrient
const KCAL_PER_G_PROTEIN: f64 = 4.0;
const KCAL_PER_G_CARBS: f64 = 4.0;
const KCAL_PER_G_FAT: f64 = 9.0;
struct Ingredient {
name: &'static str,
grams: f64,
// Nutritional values per 100g:
protein_per_100g: f64,
fat_per_100g: f64,
carbs_per_100g: f64,
}
fn main() {
// === TARGET VALUES (edit these) ===
let target_kcal = 300.0;
let target_protein = 15.0;
let target_fat = 23.0;
let target_carbs = 8.0;
// === TOLERANCE (how far off is acceptable, in %) ===
let kcal_over_pct = 12.5;
let kcal_under_pct = 12.5;
let protein_over_pct = 12.5;
let protein_under_pct = 12.5;
let fat_over_pct = 12.5;
let fat_under_pct = 12.5;
let carbs_over_pct = 12.5;
let carbs_under_pct = 12.5;
// === INGREDIENTS (edit nutritional values per 100g) ===
// Note: kcal is calculated automatically (protein*4 + carbs*4 + fat*9)
let ingredients = vec![
Ingredient {
name: "Greek Yogurt (5%)",
grams: 150.0,
protein_per_100g: 8.7,
fat_per_100g: 5.0,
carbs_per_100g: 3.3,
},
Ingredient {
name: "Walnuts",
grams: 21.0,
protein_per_100g: 15.0,
fat_per_100g: 65.0,
carbs_per_100g: 5.0,
},
Ingredient {
name: "Raspberries",
grams: 25.0,
protein_per_100g: 1.25,
fat_per_100g: 0.25,
carbs_per_100g: 5.0,
},
];
// === CALCULATION (no need to edit below) ===
let mut total_kcal = 0.0;
let mut total_protein = 0.0;
let mut total_fat = 0.0;
let mut total_carbs = 0.0;
println!("INGREDIENT BREAKDOWN");
println!("{:-<75}", "");
for ing in &ingredients {
let mult = ing.grams / 100.0;
let ing_protein = ing.protein_per_100g * mult;
let ing_fat = ing.fat_per_100g * mult;
let ing_carbs = ing.carbs_per_100g * mult;
let ing_kcal = (ing_protein * KCAL_PER_G_PROTEIN)
+ (ing_carbs * KCAL_PER_G_CARBS)
+ (ing_fat * KCAL_PER_G_FAT);
total_kcal += ing_kcal;
total_protein += ing_protein;
total_fat += ing_fat;
total_carbs += ing_carbs;
println!("{:<20} {:>5.0}g | {:>5.0} kcal | {:>5.1}g P | {:>5.1}g F | {:>5.1}g C",
ing.name, ing.grams, ing_kcal, ing_protein, ing_fat, ing_carbs);
}
println!("{:-<75}", "");
println!("{:<20} {:>6} | {:>5.0} kcal | {:>5.1}g P | {:>5.1}g F | {:>5.1}g C",
"TOTAL", "", total_kcal, total_protein, total_fat, total_carbs);
println!("{:<20} {:>6} | {:>5.0} kcal | {:>5.1}g P | {:>5.1}g F | {:>5.1}g C",
"TARGET", "", target_kcal, target_protein, target_fat, target_carbs);
println!("\n{:-<75}", "");
println!("VERDICT");
println!("{:-<75}", "");
let kcal_ok = total_kcal <= target_kcal * (1.0 + kcal_over_pct / 100.0)
&& total_kcal >= target_kcal * (1.0 - kcal_under_pct / 100.0);
let protein_ok = total_protein <= target_protein * (1.0 + protein_over_pct / 100.0)
&& total_protein >= target_protein * (1.0 - protein_under_pct / 100.0);
let fat_ok = total_fat <= target_fat * (1.0 + fat_over_pct / 100.0)
&& total_fat >= target_fat * (1.0 - fat_under_pct / 100.0);
let carbs_ok = total_carbs <= target_carbs * (1.0 + carbs_over_pct / 100.0)
&& total_carbs >= target_carbs * (1.0 - carbs_under_pct / 100.0);
let kcal_diff = total_kcal - target_kcal;
let kcal_diff_pct = (kcal_diff / target_kcal) * 100.0;
let kcal_status = if kcal_ok { "OK" } else if kcal_diff > 0.0 { "HIGH" } else { "LOW" };
println!("Kcal: {} ({:.0} / {:.0}, {:+.0} kcal, {:+.0}%)",
kcal_status, total_kcal, target_kcal, kcal_diff, kcal_diff_pct);
let protein_diff = total_protein - target_protein;
let protein_diff_pct = (protein_diff / target_protein) * 100.0;
let protein_status = if protein_ok { "OK" } else if protein_diff > 0.0 { "HIGH" } else { "LOW" };
println!("Protein: {} ({:.1}g / {:.1}g, {:+.1}g, {:+.0}%)",
protein_status, total_protein, target_protein, protein_diff, protein_diff_pct);
let fat_diff = total_fat - target_fat;
let fat_diff_pct = (fat_diff / target_fat) * 100.0;
let fat_status = if fat_ok { "OK" } else if fat_diff > 0.0 { "HIGH" } else { "LOW" };
println!("Fat: {} ({:.1}g / {:.1}g, {:+.1}g, {:+.0}%)",
fat_status, total_fat, target_fat, fat_diff, fat_diff_pct);
let carbs_diff = total_carbs - target_carbs;
let carbs_diff_pct = (carbs_diff / target_carbs) * 100.0;
let carbs_status = if carbs_ok { "OK" } else if carbs_diff > 0.0 { "HIGH" } else { "LOW" };
println!("Carbs: {} ({:.1}g / {:.1}g, {:+.1}g, {:+.0}%)",
carbs_status, total_carbs, target_carbs, carbs_diff, carbs_diff_pct);
if kcal_ok && protein_ok && fat_ok && carbs_ok {
println!("\n✓ This meal hits all targets!");
} else {
println!("\n✗ Issues:");
if !kcal_ok {
let diff = total_kcal - target_kcal;
let pct = (diff / target_kcal) * 100.0;
if diff > 0.0 {
println!(" - Kcal too high: {:.0} over ({:+.0}%)", diff, pct);
} else {
println!(" - Kcal too low: {:.0} under ({:-.0}%)", -diff, pct);
}
}
if !protein_ok {
let diff = total_protein - target_protein;
let pct = (diff / target_protein) * 100.0;
if diff > 0.0 {
println!(" - Protein too high: {:.1}g over ({:+.0}%)", diff, pct);
} else {
println!(" - Protein too low: {:.1}g under ({:-.0}%)", -diff, pct);
}
}
if !fat_ok {
let diff = total_fat - target_fat;
let pct = (diff / target_fat) * 100.0;
if diff > 0.0 {
println!(" - Fat too high: {:.1}g over ({:+.0}%)", diff, pct);
} else {
println!(" - Fat too low: {:.1}g under ({:-.0}%)", -diff, pct);
}
}
if !carbs_ok {
let diff = total_carbs - target_carbs;
let pct = (diff / target_carbs) * 100.0;
if diff > 0.0 {
println!(" - Carbs too high: {:.1}g over ({:+.0}%)", diff, pct);
} else {
println!(" - Carbs too low: {:.1}g under ({:-.0}%)", -diff, pct);
}
}
}
}
Dinner
Target: ~550 kcal · 50g protein · 36g fat · 7g net carbs
A lighter, often cold or quick-prep meal. This is when the house is usually most chaotic, so cooking complexity stays low.
The Goal: High protein but lower “bulk” than lunch. Think eggs, cold cuts (Jamón), or cheese.
The Logic: Keeping this meal moderate in calories ensures you aren’t going to bed with a heavily laboring digestive system, but the 50g of protein ensures your body doesn’t enter a catabolic (muscle-burning) state overnight.