If i am just running everyday will it improve my running or not
| Run Type | Purpose | % of Weekly Runs |
|---|---|---|
| Easy / recovery runs | Build aerobic base, recover | 70-80% |
| Tempo runs | Improve lactate threshold | 10-15% |
| Intervals / speedwork | Boost VO2 max | 5-10% |
| Long runs | Build endurance, fat adaptation | 1x/week |
| Day | Session |
|---|---|
| Monday | Easy run (30-40 min) |
| Tuesday | Intervals (e.g., 6x400m at hard effort) |
| Wednesday | Rest or cross-training |
| Thursday | Tempo run (20-30 min at comfortably hard pace) |
| Friday | Easy run or rest |
| Saturday | Long run (45-90 min easy) |
| Sunday | Full rest or walk |
How do I know if I'm overtraining vs building fitness?
My goal is 1600m in 4.5-5.0minutes
| Signal | Building Fitness | Overtraining |
|---|---|---|
| Fatigue | Tired after hard sessions, recovered next day | Tired all the time, even after rest days |
| Performance | Gradually improving over weeks | Declining or flatlined despite more effort |
| Sleep | Normal or slightly deeper | Disrupted, restless, or sleeping too much |
| Mood | Motivated, occasional tiredness | Irritable, anxious, low motivation, dread runs |
| Resting heart rate | Stable | Elevated 5-10+ BPM above normal |
| Soreness | Localized, fades in 24-48h | Persistent, widespread, doesn't go away |
| Illness | Rare | Frequent colds, infections (suppressed immunity) |
| Appetite | Normal to increased | Suppressed or abnormally increased |
| Day | Session | Details |
|---|---|---|
| Monday | Speed intervals | 8-10 x 200m at faster than goal pace (e.g. 35-38 sec per 200m), 90 sec rest |
| Tuesday | Easy run | 25-35 min at comfortable conversational pace |
| Wednesday | Threshold run | 3 x 1000m at goal race pace (4:30-5:00/km), 2 min rest |
| Thursday | Rest or easy walk | Full recovery |
| Friday | VO2 max intervals | 5 x 400m at slightly faster than race pace, 2-3 min rest |
| Saturday | Easy run + strides | 30 min easy + 4-6 x 80m accelerations |
| Sunday | Full rest | No running |
| 400m time | Projected 1600m |
|---|---|
| 60-65 sec | ~4:30-4:45 |
| 65-70 sec | ~4:45-5:10 |
| 70-75 sec | ~5:15-5:40 |
1600 time is 7minutes
| Current | Goal | Gap | |
|---|---|---|---|
| 1600m time | 7:00 | 4:30-5:00 | 2:00-2:30 faster |
| Per 400m | ~105 sec | 68-75 sec | ~30-37 sec/lap |
| Per km pace | 4:22/km | 2:49-3:08/km | ... |
| Day | Session |
|---|---|
| Mon | Easy 20-30 min (comfortable, can talk) |
| Tue | 6 x 400m at current 1600m pace (105 sec each), 90 sec rest |
| Wed | Rest |
| Thu | Easy 25 min + 4 strides (80m fast accelerations) |
| Fri | Rest |
| Sat | 3 x 600m at slightly faster than 1600m pace, 2 min rest |
| Sun | Rest |
| Day | Session |
|---|---|
| Mon | Easy 30 min |
| Tue | 8 x 200m at target pace (85-90 sec per 400m effort), 60 sec rest |
| Wed | Easy 25 min |
| Thu | 4 x 400m at 90-95 sec, 2 min rest |
| Fri | Rest |
| Sat | 2 x 800m at 3:10-3:20, 3 min rest |
| Sun | Rest |
| Month | Expected 1600m Time |
|---|---|
| Now | 7:00 |
| Month 2 | 6:20-6:30 |
| Month 4 | 5:45-6:00 |
| Month 6 | 5:10-5:30 |
| Month 9-12 | 4:30-5:00 (goal) |
I was following a running plan which was given by a insta athlete but recently he stop the series His workouts was like Monday long run 35 , 40,50 alternatively Tuesday recovery run wed intervals Thu recovery run Fri hard run Sat long run Sun rest
| Day | Session | Verdict |
|---|---|---|
| Mon | Long run 35/40/50 min | ✅ Good for aerobic base |
| Tue | Recovery run | ✅ Smart after long run |
| Wed | Intervals | ✅ Best session of the week |
| Thu | Recovery run | ✅ Fine |
| Fri | Hard run | ⚠️ Vague - what kind of hard? |
| Sat | Long run | ❌ Problem (see below) |
| Sun | Rest | ✅ |
| Day | Session | Details |
|---|---|---|
| Mon | Long run | 35 min easy (Week 1), 40 min (Week 2), 45 min (Week 3) - conversational pace |
| Tue | Recovery run | 20-25 min very easy, legs loosening only |
| Wed | Intervals | The most important session (see below) |
| Thu | Recovery run | 20 min easy OR full rest if legs feel heavy |
| Fri | Speed session | Specific 200m/400m reps (not just "hard run") |
| Sat | Strides + easy | 20 min easy + 6 x 80m fast accelerations |
| Sun | Full rest | No running |
| Week | Session |
|---|---|
| 1-2 | 6 x 400m at current pace (105 sec), 90 sec rest |
| 3-4 | 8 x 400m at 100 sec, 90 sec rest |
| 5-6 | 6 x 400m at 95 sec, 2 min rest |
| 7-8 | 5 x 600m at 95 sec/400m effort, 2 min rest |
| 9-10 | 4 x 800m at 3:15-3:20, 3 min rest |
| Week | Session |
|---|---|
| 1-2 | 8 x 200m at 48-50 sec, 60 sec rest |
| 3-4 | 10 x 200m at 46-48 sec, 60 sec rest |
| 5-6 | 6 x 300m at 72-75 sec, 90 sec rest |
| 7-8 | 4 x 400m at 88-92 sec, 2 min rest |
| 9-10 | 3 x 600m at 2:15-2:20, 2 min rest |
Create a 12-week training plan with exact paces and splits for 1600m
mkdir -p /tmp/workspace/running-plan && ls /tmp/workspace/running-plan/
~/running-plan/generate_plan.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import mm, cm
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, PageBreak, KeepTogether
)
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT
from reportlab.platypus import BaseDocTemplate, Frame, PageTemplate
OUTPUT = "/tmp/workspace/running-plan/1600m_12week_plan.pdf"
# ── Colours ──────────────────────────────────────────────────────────────────
C_DARK = colors.HexColor("#1A1A2E")
C_BLUE = colors.HexColor("#16213E")
C_ACCENT = colors.HexColor("#E94560")
C_GOLD = colors.HexColor("#F5A623")
C_GREEN = colors.HexColor("#27AE60")
C_LIGHT = colors.HexColor("#ECF0F1")
C_MID = colors.HexColor("#BDC3C7")
C_WHITE = colors.white
C_EASY = colors.HexColor("#D5F5E3") # green tint
C_HARD = colors.HexColor("#FADBD8") # red tint
C_INTER = colors.HexColor("#D6EAF8") # blue tint
C_REST = colors.HexColor("#F2F3F4") # grey
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
rightMargin=15*mm, leftMargin=15*mm,
topMargin=15*mm, bottomMargin=15*mm,
title="12-Week 1600m Training Plan",
author="Orris Training"
)
styles = getSampleStyleSheet()
def S(name, **kw):
return ParagraphStyle(name, **kw)
title_style = S("Title2", fontSize=26, textColor=C_WHITE,
fontName="Helvetica-Bold", alignment=TA_CENTER, spaceAfter=4)
sub_style = S("Sub", fontSize=13, textColor=C_GOLD,
fontName="Helvetica-Bold", alignment=TA_CENTER, spaceAfter=2)
body_style = S("Body2", fontSize=9, textColor=C_DARK,
fontName="Helvetica", leading=13, spaceAfter=4)
h1_style = S("H1", fontSize=14, textColor=C_WHITE,
fontName="Helvetica-Bold", alignment=TA_CENTER, spaceAfter=3)
h2_style = S("H2", fontSize=11, textColor=C_ACCENT,
fontName="Helvetica-Bold", spaceAfter=3, spaceBefore=6)
note_style = S("Note", fontSize=8, textColor=colors.HexColor("#555555"),
fontName="Helvetica-Oblique", leading=11)
cell_style = S("Cell", fontSize=8, textColor=C_DARK,
fontName="Helvetica", leading=10)
cell_bold = S("CellB", fontSize=8, textColor=C_DARK,
fontName="Helvetica-Bold", leading=10)
cell_head = S("CellH", fontSize=8, textColor=C_WHITE,
fontName="Helvetica-Bold", leading=10, alignment=TA_CENTER)
phase_style = S("Phase", fontSize=10, textColor=C_WHITE,
fontName="Helvetica-Bold", alignment=TA_CENTER)
# ── Helper: coloured banner ───────────────────────────────────────────────────
def banner(text, bg=C_BLUE, style=h1_style, pad=6):
tbl = Table([[Paragraph(text, style)]], colWidths=[180*mm])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), bg),
("TOPPADDING", (0,0), (-1,-1), pad),
("BOTTOMPADDING",(0,0),(-1,-1), pad),
("LEFTPADDING", (0,0), (-1,-1), 8),
("RIGHTPADDING",(0,0), (-1,-1), 8),
("ROUNDEDCORNERS", [4]),
]))
return tbl
# ── Pace reference table ──────────────────────────────────────────────────────
def pace_table():
headers = ["Run Type", "Effort Feel", "Pace (per km)", "Heart Rate"]
rows = [
["Easy / Recovery", "Can hold full conversation", "6:30 – 7:30 /km", "60–70% max HR"],
["Aerobic / Long", "Comfortable, slight effort", "6:00 – 6:30 /km", "65–75% max HR"],
["Tempo", "Comfortably hard, can't talk", "5:00 – 5:30 /km","80–87% max HR"],
["Interval (1600m pace)", "Hard, race effort", "4:22 /km (current)", "88–95% max HR"],
["Speed / 200m reps","Very fast, near sprint", "3:45 – 4:00 /km", "95–100% max HR"],
]
col_w = [40*mm, 52*mm, 46*mm, 42*mm]
data = [[Paragraph(h, cell_head) for h in headers]]
bg_cycle = [C_EASY, C_INTER, C_HARD]
for i, r in enumerate(rows):
data.append([Paragraph(r[0], cell_bold)] +
[Paragraph(x, cell_style) for x in r[1:]])
tbl = Table(data, colWidths=col_w, repeatRows=1)
ts = TableStyle([
("BACKGROUND", (0,0), (-1,0), C_DARK),
("ROWBACKGROUNDS",(0,1), (-1,-1), [C_EASY, C_LIGHT, C_INTER, C_LIGHT, C_HARD]),
("GRID", (0,0), (-1,-1), 0.5, C_MID),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
])
tbl.setStyle(ts)
return tbl
# ── Weekly schedule builder ───────────────────────────────────────────────────
DAY_COLS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
def week_table(week_num, phase, sessions, note=""):
"""sessions = list of 7 dicts: {label, detail, color}"""
header_data = [
Paragraph(f"WEEK {week_num}", cell_head),
Paragraph(f"Phase: {phase}", cell_head),
Paragraph(note, cell_head),
]
# Day header row
day_row = [Paragraph(d, cell_head) for d in DAY_COLS]
# Content row
content_row = []
row_bg = []
for s in sessions:
txt = f"<b>{s['label']}</b><br/><font size=7>{s['detail']}</font>"
content_row.append(Paragraph(txt, cell_style))
row_bg.append(s.get("color", C_LIGHT))
col_w = [180*mm / 7] * 7
data = [day_row, content_row]
tbl = Table(data, colWidths=col_w)
ts = TableStyle([
("BACKGROUND", (0,0), (-1,0), C_BLUE),
("GRID", (0,0), (-1,-1), 0.4, C_MID),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 3),
("VALIGN", (0,0), (-1,-1), "TOP"),
("FONTSIZE", (0,0), (-1,-1), 7.5),
])
for i, c in enumerate(row_bg):
ts.add("BACKGROUND", (i,1), (i,1), c)
tbl.setStyle(ts)
# Week header
hdr = Table([[
Paragraph(f"WEEK {week_num}", cell_bold),
Paragraph(f"Phase: {phase}", cell_style),
Paragraph(note, note_style),
]], colWidths=[25*mm, 60*mm, 95*mm])
hdr.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_ACCENT),
("TEXTCOLOR", (0,0), (-1,-1), C_WHITE),
("TOPPADDING", (0,0), (-1,-1), 3),
("BOTTOMPADDING", (0,0), (-1,-1), 3),
("LEFTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
return [hdr, tbl, Spacer(1, 4*mm)]
# ── Define all 12 weeks ───────────────────────────────────────────────────────
E = C_EASY # easy
H = C_HARD # hard
I = C_INTER # intervals
R = C_REST # rest/recovery
T = colors.HexColor("#FDEBD0") # tempo / orange tint
def w(label, detail, color=C_LIGHT):
return {"label": label, "detail": detail, "color": color}
WEEKS = [
# ── PHASE 1: Aerobic Base (Weeks 1-4) ────────────────────────────────────
{
"week": 1, "phase": "Aerobic Base",
"note": "Build easy mileage. All runs feel comfortable.",
"sessions": [
w("Long Run","35 min @ 6:30-7:00/km\nConversational", E),
w("Recovery","20 min @ 7:00-7:30/km\nVery easy", R),
w("Intervals","6 x 400m @ 1:45\n(4:22/km pace)\nRest: 90 sec jog", I),
w("Recovery","20 min @ 7:00-7:30/km", R),
w("Strides","20 min easy +\n6 x 80m strides\n(relaxed fast)", E),
w("Long Run","35 min @ 6:30-7:00/km", E),
w("REST","Full rest or\n10 min walk", R),
]
},
{
"week": 2, "phase": "Aerobic Base",
"note": "Repeat Week 1 structure. Push interval pace slightly.",
"sessions": [
w("Long Run","40 min @ 6:30/km", E),
w("Recovery","20 min @ 7:00/km", R),
w("Intervals","6 x 400m @ 1:42\nRest: 90 sec jog", I),
w("Recovery","20 min easy", R),
w("Speed","8 x 200m @ 50 sec\nRest: 60 sec", H),
w("Easy Run","30 min @ 6:30/km", E),
w("REST","Full rest", R),
]
},
{
"week": 3, "phase": "Aerobic Base",
"note": "Increase interval volume. Easy days stay easy.",
"sessions": [
w("Long Run","40 min @ 6:20/km", E),
w("Recovery","25 min @ 7:00/km", R),
w("Intervals","8 x 400m @ 1:42\nRest: 90 sec jog", I),
w("Recovery","20 min easy", R),
w("Speed","10 x 200m @ 49 sec\nRest: 60 sec", H),
w("Easy Run","30 min +\n4 x 80m strides", E),
w("REST","Full rest", R),
]
},
{
"week": 4, "phase": "Aerobic Base – Deload",
"note": "⬇ Deload week. Cut volume 30%. Let body absorb training.",
"sessions": [
w("Easy Run","30 min @ 6:30/km\nLight effort", E),
w("Recovery","20 min @ 7:00/km", R),
w("Intervals","5 x 400m @ 1:42\nRest: 2 min", I),
w("REST","Full rest", R),
w("Speed","6 x 200m @ 50 sec\nRest: 90 sec", H),
w("Easy Run","25 min easy", E),
w("REST","Full rest", R),
]
},
# ── PHASE 2: Speed Development (Weeks 5-8) ───────────────────────────────
{
"week": 5, "phase": "Speed Development",
"note": "TIME TRIAL on Wed. Note your 1600m time.",
"sessions": [
w("Long Run","40 min @ 6:00-6:30/km", E),
w("Recovery","25 min @ 7:00/km", R),
w("TIME TRIAL","1600m solo TT\nWarm up 10 min\nGoal: beat 7:00\nCool down 10 min", H),
w("Recovery","20 min very easy", R),
w("Speed","6 x 300m @ 1:12\n(4:00/km pace)\nRest: 2 min", H),
w("Easy Run","35 min +\n4 strides", E),
w("REST","Full rest", R),
]
},
{
"week": 6, "phase": "Speed Development",
"note": "Focus: faster 200m reps. Full rest between sets.",
"sessions": [
w("Long Run","45 min @ 6:00/km", E),
w("Recovery","25 min easy", R),
w("Intervals","6 x 400m @ 1:38\n(target: 1:35 in 2 wks)\nRest: 2 min", I),
w("Recovery","20 min easy", R),
w("Speed","8 x 200m @ 47 sec\nRest: 75 sec", H),
w("Easy Run","30 min easy", E),
w("REST","Full rest", R),
]
},
{
"week": 7, "phase": "Speed Development",
"note": "Introduce 600m reps. Pace = current 1600m race effort.",
"sessions": [
w("Long Run","45 min @ 6:00/km", E),
w("Recovery","25 min easy", R),
w("Intervals","5 x 600m @ 2:35\n(4:18/km pace)\nRest: 2.5 min", I),
w("Recovery","20 min easy", R),
w("Speed","6 x 300m @ 1:10\nRest: 2 min", H),
w("Easy Run","30 min +\n6 strides", E),
w("REST","Full rest", R),
]
},
{
"week": 8, "phase": "Speed Dev – Deload",
"note": "⬇ Deload. Reduce volume 30%. Keep intensity.",
"sessions": [
w("Easy Run","30 min @ 6:30/km", E),
w("Recovery","20 min easy", R),
w("Intervals","4 x 600m @ 2:33\nRest: 2.5 min", I),
w("REST","Full rest", R),
w("Speed","5 x 200m @ 46 sec\nRest: 90 sec", H),
w("Easy Run","25 min easy", E),
w("REST","Full rest", R),
]
},
# ── PHASE 3: Race-Specific (Weeks 9-12) ──────────────────────────────────
{
"week": 9, "phase": "Race-Specific",
"note": "TIME TRIAL. Target: 6:00-6:20. Push hard.",
"sessions": [
w("Long Run","40 min @ 5:50/km", E),
w("Recovery","25 min easy", R),
w("TIME TRIAL","1600m solo TT\nTarget: sub 6:20\nWarm up 10 min", H),
w("Recovery","20 min very easy", R),
w("Intervals","4 x 800m @ 3:20\n(4:10/km pace)\nRest: 3 min", I),
w("Easy Run","30 min +\n4 strides", E),
w("REST","Full rest", R),
]
},
{
"week": 10, "phase": "Race-Specific",
"note": "Peak training week. Hardest volume of the plan.",
"sessions": [
w("Long Run","45 min @ 5:45/km", E),
w("Recovery","25 min easy", R),
w("Intervals","6 x 400m @ 1:30\n(3:45/km pace)\nRest: 2 min", I),
w("Recovery","20 min easy", R),
w("Tempo","3 x 1000m @ 4:40/km\nRest: 2.5 min", T),
w("Easy Run","30 min easy +\n6 strides", E),
w("REST","Full rest", R),
]
},
{
"week": 11, "phase": "Race-Specific",
"note": "Sharpen speed. Reps shorter, faster, fully rested.",
"sessions": [
w("Easy Run","35 min @ 6:00/km", E),
w("Recovery","20 min easy", R),
w("Intervals","8 x 300m @ 1:07\n(3:44/km pace)\nRest: 2.5 min", I),
w("Recovery","20 min easy", R),
w("Speed","4 x 400m @ 1:28\nRest: 3 min\n(near goal pace)", H),
w("Easy Run","25 min easy", E),
w("REST","Full rest", R),
]
},
{
"week": 12, "phase": "PEAK & TEST WEEK",
"note": "⬇ Taper. Fresh legs. TIME TRIAL on Sat — go for your best.",
"sessions": [
w("Easy Run","25 min @ 6:30/km\nFeel fresh", E),
w("Recovery","15 min very easy", R),
w("Sharpener","4 x 200m @ 44 sec\nFull 3 min rest\nFeel fast, not tired", I),
w("REST","Full rest\nStay off feet", R),
w("Strides Only","10 min easy +\n4 x 80m strides", E),
w("TIME TRIAL","RACE DAY\n1600m Full Effort\nWarm up 15 min\nTarget: sub 5:30", H),
w("REST","Celebrate &\nrecover", R),
]
},
]
# ── Progress milestones table ─────────────────────────────────────────────────
def milestones_table():
headers = ["Week", "Time Trial", "Target 1600m", "Key Fitness Marker"]
rows = [
["1", "—", "Baseline: 7:00", "Completing 6x400m without stopping"],
["4", "—", "Est. 6:30-6:45", "Easy runs feel genuinely easy"],
["5", "✓ TT", "Target: sub 6:30","400m reps at 1:42 feel manageable"],
["8", "—", "Est. 6:00-6:15", "600m reps holding 4:15-4:20/km"],
["9", "✓ TT", "Target: sub 6:20","800m reps at 3:20 completed"],
["12", "✓ RACE DAY", "Target: sub 5:30","All reps faster than Week 1 by 15+ sec"],
]
col_w = [15*mm, 25*mm, 50*mm, 90*mm]
data = [[Paragraph(h, cell_head) for h in headers]]
for i, r in enumerate(rows):
bg = C_HARD if "TT" in r[1] or "RACE" in r[1] else C_LIGHT
data.append([Paragraph(x, cell_bold if i==5 else cell_style) for x in r])
tbl = Table(data, colWidths=col_w, repeatRows=1)
ts = TableStyle([
("BACKGROUND", (0,0), (-1,0), C_DARK),
("ROWBACKGROUNDS",(0,1), (-1,-1), [C_LIGHT, C_LIGHT, C_HARD, C_LIGHT, C_HARD, C_EASY]),
("GRID", (0,0), (-1,-1), 0.5, C_MID),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
])
tbl.setStyle(ts)
return tbl
# ── Overtraining signals table ────────────────────────────────────────────────
def overtraining_table():
headers = ["Signal", "OK (Building)", "Warning (Overtraining)"]
rows = [
["Resting HR (morning)", "Stable / slightly lower", "+7 BPM above baseline 2+ days"],
["Energy on easy runs", "Comfortable, relaxed", "Legs heavy, effort feels harder"],
["Interval performance", "Same or improving", "Splits getting slower each week"],
["Sleep", "Normal to deeper", "Disrupted, waking at night"],
["Mood", "Motivated", "Dreading runs, irritable"],
["Recovery time", "Sore for 24-36 hrs", "Still sore after 48+ hrs"],
]
col_w = [45*mm, 65*mm, 70*mm]
data = [[Paragraph(h, cell_head) for h in headers]]
for r in rows:
data.append([Paragraph(r[0], cell_bold), Paragraph(r[1], cell_style), Paragraph(r[2], cell_style)])
tbl = Table(data, colWidths=col_w, repeatRows=1)
ts = TableStyle([
("BACKGROUND", (0,0), (-1,0), C_DARK),
("ROWBACKGROUNDS",(0,1), (-1,-1), [C_EASY, C_LIGHT]),
("GRID", (0,0), (-1,-1), 0.5, C_MID),
("TOPPADDING", (0,0), (-1,-1), 4),
("BOTTOMPADDING", (0,0), (-1,-1), 4),
("LEFTPADDING", (0,0), (-1,-1), 5),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
])
tbl.setStyle(ts)
return tbl
# ── Build document ────────────────────────────────────────────────────────────
story = []
# ── Cover header ──────────────────────────────────────────────────────────────
cover = Table([[
Paragraph("12-WEEK 1600m TRAINING PLAN", title_style),
Paragraph("Current: 7:00 → Goal: Sub 5:30", sub_style),
Paragraph("Starting pace: 4:22/km | Target: 3:26/km | Phases: 3",
S("sub2", fontSize=10, textColor=C_MID, fontName="Helvetica",
alignment=TA_CENTER)),
]], colWidths=[180*mm])
cover.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), C_DARK),
("TOPPADDING", (0,0), (-1,-1), 12),
("BOTTOMPADDING", (0,0), (-1,-1), 12),
("ALIGN", (0,0), (-1,-1), "CENTER"),
]))
story.append(cover)
story.append(Spacer(1, 6*mm))
# ── Pace Legend ───────────────────────────────────────────────────────────────
story.append(banner("PACE REFERENCE GUIDE", C_BLUE))
story.append(Spacer(1, 2*mm))
story.append(pace_table())
story.append(Spacer(1, 4*mm))
# ── Colour key ────────────────────────────────────────────────────────────────
key_data = [
[Paragraph("COLOUR KEY:", cell_bold),
Paragraph(" Easy / Long Run", S("ck", fontSize=8, backColor=C_EASY, fontName="Helvetica")),
Paragraph(" Intervals / Speed", S("ck2", fontSize=8, backColor=C_INTER, fontName="Helvetica")),
Paragraph(" Hard / Time Trial", S("ck3", fontSize=8, backColor=C_HARD, fontName="Helvetica")),
Paragraph(" Tempo", S("ck4", fontSize=8, backColor=T, fontName="Helvetica")),
Paragraph(" Rest / Recovery", S("ck5", fontSize=8, backColor=C_REST, fontName="Helvetica")),
]
]
key_tbl = Table(key_data, colWidths=[25*mm, 32*mm, 36*mm, 34*mm, 24*mm, 29*mm])
key_tbl.setStyle(TableStyle([
("BACKGROUND", (1,0),(1,0), C_EASY),
("BACKGROUND", (2,0),(2,0), C_INTER),
("BACKGROUND", (3,0),(3,0), C_HARD),
("BACKGROUND", (4,0),(4,0), T),
("BACKGROUND", (5,0),(5,0), C_REST),
("TOPPADDING", (0,0),(-1,-1), 4),
("BOTTOMPADDING", (0,0),(-1,-1), 4),
("LEFTPADDING", (0,0),(-1,-1), 4),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
]))
story.append(key_tbl)
story.append(Spacer(1, 5*mm))
# ── Phase banners + weeks ─────────────────────────────────────────────────────
phase_defs = [
(1, 4, "PHASE 1: AEROBIC BASE", "Build mileage and running economy. Intervals at current pace.", C_GREEN),
(5, 8, "PHASE 2: SPEED DEVELOPMENT", "Faster reps, introduce 600m. First time trial Week 5.", C_GOLD),
(9, 12, "PHASE 3: RACE-SPECIFIC", "Near-goal pace work. Taper. Full time trial Week 12.", C_ACCENT),
]
phase_idx = 0
for wk in WEEKS:
wnum = wk["week"]
# Insert phase banner at start of each phase
for (ps, pe, ptitle, pdesc, pcol) in phase_defs:
if wnum == ps:
story.append(PageBreak() if wnum > 1 else Spacer(1, 1*mm))
ph_tbl = Table([[
Paragraph(ptitle, S("PT", fontSize=13, textColor=C_WHITE,
fontName="Helvetica-Bold", alignment=TA_CENTER)),
Paragraph(pdesc, S("PD", fontSize=9, textColor=C_LIGHT,
fontName="Helvetica", alignment=TA_CENTER)),
]], colWidths=[180*mm])
ph_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0), (-1,-1), pcol),
("TOPPADDING", (0,0), (-1,-1), 8),
("BOTTOMPADDING", (0,0), (-1,-1), 8),
("ALIGN", (0,0), (-1,-1), "CENTER"),
]))
story.append(ph_tbl)
story.append(Spacer(1, 4*mm))
rows = week_table(wnum, wk["phase"], wk["sessions"], wk["note"])
for r in rows:
story.append(r)
# ── Progress milestones ───────────────────────────────────────────────────────
story.append(PageBreak())
story.append(banner("PROGRESS MILESTONES & TIME TRIALS", C_DARK))
story.append(Spacer(1, 3*mm))
story.append(milestones_table())
story.append(Spacer(1, 6*mm))
# ── Overtraining guide ────────────────────────────────────────────────────────
story.append(banner("OVERTRAINING vs. BUILDING FITNESS", C_BLUE))
story.append(Spacer(1, 3*mm))
story.append(overtraining_table())
story.append(Spacer(1, 4*mm))
# ── Key rules ─────────────────────────────────────────────────────────────────
story.append(banner("5 GOLDEN RULES", C_DARK))
story.append(Spacer(1, 3*mm))
rules = [
("1. 80/20 Rule", "80% of runs = easy. Only 20% hard. If your easy runs feel hard, slow down."),
("2. 10% Rule", "Never increase total weekly mileage by more than 10% per week."),
("3. Deload every 4th week", "Cut volume 30% every 4th week. This is when fitness actually improves."),
("4. Morning HR check", "Take resting HR daily. If 7+ BPM above normal, take an extra rest day."),
("5. Intervals = quality", "If your splits are slowing down mid-session, stop. Don't grind through bad reps."),
]
rules_data = [[Paragraph(r[0], cell_bold), Paragraph(r[1], cell_style)] for r in rules]
rules_tbl = Table(rules_data, colWidths=[50*mm, 130*mm])
rules_tbl.setStyle(TableStyle([
("ROWBACKGROUNDS", (0,0), (-1,-1), [C_LIGHT, C_EASY]),
("GRID", (0,0), (-1,-1), 0.4, C_MID),
("TOPPADDING", (0,0), (-1,-1), 5),
("BOTTOMPADDING", (0,0), (-1,-1), 5),
("LEFTPADDING", (0,0), (-1,-1), 6),
("VALIGN", (0,0), (-1,-1), "MIDDLE"),
]))
story.append(rules_tbl)
story.append(Spacer(1, 5*mm))
story.append(Paragraph(
"Generated by Orris Training Assistant | Start date: August 12, 2026 | "
"All paces are guidelines — adjust based on how you feel each day.",
S("footer", fontSize=7.5, textColor=C_MID, alignment=TA_CENTER, fontName="Helvetica-Oblique")
))
# ── Build ─────────────────────────────────────────────────────────────────────
doc.build(story)
print(f"PDF saved: {OUTPUT}")
cd /tmp/workspace/running-plan && python generate_plan.py 2>&1
ls -lh /tmp/workspace/running-plan/
1600m 12week plan
PDF Document · PDF
| Phase | Weeks | Focus |
|---|---|---|
| Aerobic Base | 1-4 | Build engine. Intervals at your current pace. |
| Speed Development | 5-8 | Faster reps, 600m introduced, first time trial (Week 5). |
| Race-Specific | 9-12 | Near-goal pace, 800m reps, taper, full race test Week 12. |
Should i do 2 times running or one time. E
| Effect | What Happens |
|---|---|
| Recovery | You never fully recover between sessions - legs stay fatigued |
| Injury risk | Doubles the impact load before your body has adapted |
| Sleep/muscle repair | Recovery happens at night - two sessions per day cuts into that cycle |
| Performance | Hard sessions (intervals, speed) will suffer because legs are pre-fatigued |
Exercises
What kind of exercises are you asking about?
| Running Day | Strength Timing |
|---|---|
| Easy / Recovery days | ✅ After the run, 20-30 min |
| Interval / Hard days | ❌ Not on the same day - legs need full energy |
| Rest day (Sunday) | ✅ Optional light session if feeling good |
| Exercise | Sets x Reps | Why It Helps |
|---|---|---|
| Bulgarian Split Squat | 3 x 10 each leg | Single-leg strength, mimics running stride |
| Step-Ups (onto chair/bench) | 3 x 12 each leg | Hip drive and glute activation |
| Romanian Deadlift (bodyweight or dumbbells) | 3 x 12 | Hamstring strength - prevents injury |
| Calf Raises (slow, full range) | 4 x 20 | Propulsion off the ground |
| Glute Bridge | 3 x 15 | Glute power for uphill and sprint finish |
| Exercise | Sets x Duration | Why It Helps |
|---|---|---|
| Plank | 3 x 45 sec | Core stability = less energy wasted in upper body |
| Side Plank | 3 x 30 sec each | Hip stability, reduces side-to-side sway |
| Dead Bug | 3 x 10 each side | Anti-rotation core, posture under fatigue |
| Single-leg Glute Bridge | 3 x 12 each leg | Hip strength + balance |
| Mountain Climbers | 3 x 20 | Core endurance + hip flexor strength |
| Exercise | Sets x Reps | Cue |
|---|---|---|
| Box Jumps / Jump Squats | 4 x 6 | Land soft, explode fast |
| Bounding (exaggerated running strides) | 3 x 20m | Big push-off each step |
| Single-leg Hops | 3 x 8 each leg | Land and absorb softly |
| Ankle Hops (fast, low) | 4 x 15 | Stiff ankles = faster ground contact |
| Day | Running | Strength |
|---|---|---|
| Mon | Long run | None |
| Tue | Recovery run | Block A + B (after run) |
| Wed | Intervals | None |
| Thu | Recovery run | Block A + B (after run) |
| Fri | Speed session | None |
| Sat | Easy + strides | Optional: Block C only |
| Sun | Rest | None |
| Phase | Focus |
|---|---|
| Weeks 1-4 | Master form. Bodyweight only. High reps (15-20). |
| Weeks 5-8 | Add load (dumbbells, backpack). Medium reps (10-12). Add plyometrics. |
| Weeks 9-11 | Heavier load, lower reps (6-8). Explosive movements. |
| Week 12 | Cut strength to minimum - save legs for time trial. |
Create a printable strength routine card for my phone
mkdir -p /tmp/workspace/running-plan && ls /tmp/workspace/running-plan/
~/running-plan/generate_card.py
from reportlab.lib.pagesizes import A5
from reportlab.lib import colors
from reportlab.lib.units import mm
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, HRFlowable
)
OUTPUT = "/tmp/workspace/running-plan/strength_card.pdf"
# Phone-friendly: tall portrait, A5 (148 x 210 mm)
W, H = A5
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A5,
rightMargin=8*mm, leftMargin=8*mm,
topMargin=8*mm, bottomMargin=8*mm,
title="Runner Strength Card",
)
# ── Colours ───────────────────────────────────────────────────────────────────
C_BG = colors.HexColor("#0D0D1A")
C_ACCENT = colors.HexColor("#E94560")
C_GOLD = colors.HexColor("#F5A623")
C_GREEN = colors.HexColor("#27AE60")
C_BLUE = colors.HexColor("#1A6FA8")
C_CARD = colors.HexColor("#16213E")
C_LIGHT = colors.HexColor("#ECF0F1")
C_MID = colors.HexColor("#7F8C8D")
C_WHITE = colors.white
C_PLY = colors.HexColor("#6C3483") # purple for plyos
PAGE_W = W - 16*mm # usable width
def S(name, **kw):
return ParagraphStyle(name, **kw)
title_s = S("T", fontSize=17, textColor=C_WHITE, fontName="Helvetica-Bold",
alignment=TA_CENTER, spaceAfter=1, leading=20)
sub_s = S("Su", fontSize=9, textColor=C_GOLD, fontName="Helvetica",
alignment=TA_CENTER, spaceAfter=1)
sec_s = S("Sc", fontSize=10, textColor=C_WHITE, fontName="Helvetica-Bold",
alignment=TA_CENTER)
exname_s = S("EN", fontSize=8.5,textColor=C_WHITE, fontName="Helvetica-Bold", leading=11)
detail_s = S("D", fontSize=7.5,textColor=C_LIGHT, fontName="Helvetica", leading=10)
cue_s = S("C", fontSize=7, textColor=C_GOLD, fontName="Helvetica-Oblique",leading=9)
note_s = S("N", fontSize=7, textColor=C_MID, fontName="Helvetica-Oblique",
alignment=TA_CENTER, leading=9)
day_s = S("Dy", fontSize=7.5,textColor=C_WHITE, fontName="Helvetica-Bold", alignment=TA_CENTER)
day_d = S("Dd", fontSize=7, textColor=C_LIGHT, fontName="Helvetica", alignment=TA_CENTER, leading=9)
phase_s = S("Ph", fontSize=7.5,textColor=C_WHITE, fontName="Helvetica-Bold", alignment=TA_CENTER)
def section_banner(text, bg=C_CARD, color=C_ACCENT):
style = S("sb", fontSize=10, textColor=color, fontName="Helvetica-Bold",
alignment=TA_CENTER)
tbl = Table([[Paragraph(text, style)]], colWidths=[PAGE_W])
tbl.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), bg),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING", (0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 6),
]))
return tbl
def exercise_block(exercises, accent=C_ACCENT):
"""exercises: list of (name, sets_reps, cue)"""
rows = []
for name, sets, cue in exercises:
rows.append([
Paragraph(f"● {name}", exname_s),
Paragraph(sets, detail_s),
Paragraph(cue, cue_s),
])
col_w = [PAGE_W*0.42, PAGE_W*0.22, PAGE_W*0.36]
tbl = Table(rows, colWidths=col_w)
ts = TableStyle([
("ROWBACKGROUNDS", (0,0),(-1,-1), [C_CARD, colors.HexColor("#1E2D50")]),
("TOPPADDING", (0,0),(-1,-1), 4),
("BOTTOMPADDING", (0,0),(-1,-1), 4),
("LEFTPADDING", (0,0),(-1,-1), 4),
("RIGHTPADDING", (0,0),(-1,-1), 3),
("VALIGN", (0,0),(-1,-1), "TOP"),
("LINEBELOW", (0,0),(-1,-1), 0.3, colors.HexColor("#2C3E6B")),
("LEFTPADDING", (0,0),(0,-1), 6),
])
# accent left border simulation via background on col 0 strip
tbl.setStyle(ts)
return tbl
def schedule_row(days):
"""days: list of (day_name, session, bg_color)"""
cells = [[Paragraph(d, day_s), Paragraph(s, day_d)] for d, s, _ in days]
bgs = [c for _, _, c in days]
n = len(days)
col_w = [PAGE_W / n] * n
# Transpose: one row of day names, one row of sessions
header_row = [Paragraph(d, day_s) for d, _, _ in days]
detail_row = [Paragraph(s, day_d) for _, s, _ in days]
tbl = Table([header_row, detail_row], colWidths=col_w)
ts = TableStyle([
("TOPPADDING", (0,0),(-1,-1), 3),
("BOTTOMPADDING", (0,0),(-1,-1), 3),
("LEFTPADDING", (0,0),(-1,-1), 2),
("RIGHTPADDING", (0,0),(-1,-1), 2),
("ALIGN", (0,0),(-1,-1), "CENTER"),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
("GRID", (0,0),(-1,-1), 0.3, colors.HexColor("#2C3E6B")),
])
for i, bg in enumerate(bgs):
ts.add("BACKGROUND", (i,0),(i,0), bg)
ts.add("BACKGROUND", (i,1),(i,1), colors.HexColor("#16213E"))
tbl.setStyle(ts)
return tbl
def phase_table():
phases = [
("Wk 1-4", "Bodyweight\nHigh reps 15-20\nMaster form", C_GREEN),
("Wk 5-8", "Add load\nMed reps 10-12\n+ Plyometrics", C_GOLD),
("Wk 9-11","Heavy load\nLow reps 6-8\nExplosive", C_ACCENT),
("Wk 12", "Cut strength\nSave legs for\ntime trial", C_MID),
]
cells = [[Paragraph(p[0], S("ph", fontSize=8, textColor=C_WHITE,
fontName="Helvetica-Bold", alignment=TA_CENTER)),
Paragraph(p[1], S("pd", fontSize=7, textColor=C_LIGHT,
fontName="Helvetica", alignment=TA_CENTER, leading=9))]
for p in phases]
# Each phase: 2 rows (name + detail) in its own col
header_row = [Paragraph(p[0], S("ph2", fontSize=8, textColor=C_WHITE,
fontName="Helvetica-Bold", alignment=TA_CENTER))
for p in phases]
detail_row = [Paragraph(p[1], S("pd2", fontSize=6.5, textColor=C_LIGHT,
fontName="Helvetica", alignment=TA_CENTER, leading=8))
for p in phases]
col_w = [PAGE_W / 4] * 4
tbl = Table([header_row, detail_row], colWidths=col_w)
ts = TableStyle([
("TOPPADDING", (0,0),(-1,-1), 4),
("BOTTOMPADDING", (0,0),(-1,-1), 4),
("GRID", (0,0),(-1,-1), 0.3, colors.HexColor("#2C3E6B")),
("ALIGN", (0,0),(-1,-1), "CENTER"),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
])
for i, p in enumerate(phases):
ts.add("BACKGROUND", (i,0),(i,0), p[2])
ts.add("BACKGROUND", (i,1),(i,1), C_CARD)
tbl.setStyle(ts)
return tbl
# ── Story ─────────────────────────────────────────────────────────────────────
story = []
# ── Header ────────────────────────────────────────────────────────────────────
hdr = Table([[
Paragraph("RUNNER STRENGTH CARD", title_s),
Paragraph("1600m Training | Goal: Sub 5:30", sub_s),
]], colWidths=[PAGE_W])
hdr.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), C_BG),
("TOPPADDING", (0,0),(-1,-1), 7),
("BOTTOMPADDING", (0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 4),
]))
story.append(hdr)
story.append(Spacer(1, 2*mm))
# ── Block A: Lower Body ───────────────────────────────────────────────────────
story.append(section_banner("🦵 BLOCK A — LOWER BODY POWER (2x / week)", C_CARD, C_ACCENT))
story.append(Spacer(1, 1*mm))
col_hdr = Table([[
Paragraph("Exercise", S("ch", fontSize=7.5, textColor=C_MID, fontName="Helvetica-Bold")),
Paragraph("Sets × Reps", S("ch2", fontSize=7.5, textColor=C_MID, fontName="Helvetica-Bold")),
Paragraph("Cue", S("ch3", fontSize=7.5, textColor=C_MID, fontName="Helvetica-Bold")),
]], colWidths=[PAGE_W*0.42, PAGE_W*0.22, PAGE_W*0.36])
col_hdr.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), colors.HexColor("#0A0A14")),
("TOPPADDING", (0,0),(-1,-1), 2),
("BOTTOMPADDING", (0,0),(-1,-1), 2),
("LEFTPADDING", (0,0),(0,-1), 6),
("LEFTPADDING", (1,0),(2,-1), 4),
]))
story.append(col_hdr)
lower_body = [
("Bulgarian Split Squat", "3 × 10 / leg", "Back foot on bench"),
("Step-Ups", "3 × 12 / leg", "Drive through heel"),
("Romanian Deadlift", "3 × 12", "Hinge hips, soft knees"),
("Calf Raises", "4 × 20", "Slow down, full range"),
("Glute Bridge", "3 × 15", "Squeeze at top 1 sec"),
]
story.append(exercise_block(lower_body, C_ACCENT))
story.append(Spacer(1, 3*mm))
# ── Block B: Core ─────────────────────────────────────────────────────────────
story.append(section_banner("💪 BLOCK B — CORE & STABILITY (2x / week)", C_CARD, C_GREEN))
story.append(Spacer(1, 1*mm))
story.append(col_hdr)
core = [
("Plank", "3 × 45 sec", "Flat back, breathe"),
("Side Plank", "3 × 30 sec / side","Hip up, straight body"),
("Dead Bug", "3 × 10 / side", "Lower back on floor"),
("Single-leg Glute Bridge", "3 × 12 / leg", "Keep hips level"),
("Mountain Climbers", "3 × 20", "Fast knees, hips low"),
]
story.append(exercise_block(core, C_GREEN))
story.append(Spacer(1, 3*mm))
# ── Block C: Plyometrics ──────────────────────────────────────────────────────
story.append(section_banner("⚡ BLOCK C — PLYOMETRICS (from Week 5)", C_CARD, C_GOLD))
story.append(Spacer(1, 1*mm))
story.append(col_hdr)
plyo = [
("Jump Squats", "4 × 6", "Land soft, explode up"),
("Bounding", "3 × 20m", "Big push-off, drive arm"),
("Single-leg Hops", "3 × 8 / leg", "Absorb landing softly"),
("Ankle Hops", "4 × 15", "Fast, stiff ankles"),
]
story.append(exercise_block(plyo, C_GOLD))
story.append(Spacer(1, 3*mm))
# ── Weekly Schedule ───────────────────────────────────────────────────────────
story.append(section_banner("📅 WEEKLY SCHEDULE", C_BG, C_BLUE))
story.append(Spacer(1, 1*mm))
C_RUN = colors.HexColor("#1A4A6B")
C_STR = colors.HexColor("#1A3A2A")
C_OFF = colors.HexColor("#1A1A2E")
C_BOTH = colors.HexColor("#3D2B0A")
days_data = [
("MON", "Long Run\nNo strength", C_RUN),
("TUE", "Recovery Run\n+ Block A+B", C_BOTH),
("WED", "Intervals\nNo strength", C_RUN),
("THU", "Recovery Run\n+ Block A+B", C_BOTH),
("FRI", "Speed Session\nNo strength", C_RUN),
("SAT", "Easy + Strides\nOpt: Block C", C_STR),
("SUN", "FULL REST", C_OFF),
]
story.append(schedule_row(days_data))
story.append(Spacer(1, 3*mm))
# ── 12-Week Progression ───────────────────────────────────────────────────────
story.append(section_banner("📈 12-WEEK PROGRESSION", C_BG, C_GOLD))
story.append(Spacer(1, 1*mm))
story.append(phase_table())
story.append(Spacer(1, 3*mm))
# ── Top 3 Must-Do ─────────────────────────────────────────────────────────────
top3 = Table([[
Paragraph("🥇 TOP 3 EXERCISES FOR 1600m SPEED",
S("t3h", fontSize=9, textColor=C_GOLD, fontName="Helvetica-Bold", alignment=TA_CENTER)),
Paragraph("1. Calf Raises — propulsion off the ground\n"
"2. Bulgarian Split Squat — single-leg race power\n"
"3. Plank — core = no wasted energy per stride",
S("t3d", fontSize=7.5, textColor=C_LIGHT, fontName="Helvetica", leading=11)),
]], colWidths=[PAGE_W])
top3.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), colors.HexColor("#1A1200")),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING", (0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 8),
("LINEABOVE", (0,0),(-1,0), 1.5, C_GOLD),
("LINEBELOW", (0,-1),(-1,-1),1.5, C_GOLD),
]))
story.append(top3)
story.append(Spacer(1, 2*mm))
# ── Footer ────────────────────────────────────────────────────────────────────
story.append(Paragraph(
"Orris Training | Current: 7:00 → Goal: Sub 5:30 | Strength = Speed",
S("ft", fontSize=6.5, textColor=C_MID, fontName="Helvetica-Oblique",
alignment=TA_CENTER)
))
# ── Build ─────────────────────────────────────────────────────────────────────
doc.build(story)
print(f"Card saved: {OUTPUT}")
cd /tmp/workspace/running-plan && python generate_card.py 2>&1
ls -lh /tmp/workspace/running-plan/strength_card.pdf
strength card
PDF Document · PDF
See this planner
cd /tmp/workspace && python3 -c " import pdfplumber path = '/tmp/workspace/attachments/bd954119-c405-4a2f-9079-d1910f2d23b2/Revised_1600m_Training_Plan.pdf' with pdfplumber.open(path) as pdf: print(f'Pages: {len(pdf.pages)}') for i, page in enumerate(pdf.pages): print(f'--- PAGE {i+1} ---') print(page.extract_text()) "
| Element | Verdict |
|---|---|
| Weekly structure (Mon-Sun) | ✅ Solid - mirrors what we discussed |
| Deload on Week 4 & 8 | ✅ Correct - reduces injury risk |
| Time trials on Week 5 & 9 | ✅ Good checkpoints |
| Hill sprints on Friday | ✅ Excellent addition - builds leg power specific to 1600m |
| Pull-ups on Saturday | ✅ Smart for Army PT prep |
| 3x/week push-ups + planks | ✅ Covers upper body and core |
| Realistic goal (5:45-6:00) | ✅ Much more achievable from 7:00 in 12 weeks vs. sub-5:30 |
| Element | My Original Plan | Your Revised Plan | Winner |
|---|---|---|---|
| Goal | Sub-5:30 | 5:45-6:00 | Revised (realistic) |
| Hill work | None | Friday hills | Revised |
| Army PT prep | None | Pull-ups + push-ups | Revised |
| Exact paces | ✅ Specified | ❌ Vague | Original |
| Interval volume | Detailed | High level | Original |
| Plyometrics | Week 5 onward | Not included | Original |
How should I adjust the plan if I fall behind on timing
My goal onow Tarritorial army open rally
| Category | Male (Under 30) | Qualifying Standard |
|---|---|---|
| 1600m Run | 5:30 or faster | Pass/Fail |
| Pull-ups | 6 minimum | Pass/Fail |
| 9 feet ditch jump | Clear it | Pass/Fail |
| Zig-zag balance | Complete | Pass/Fail |
| Reason | Adjustment |
|---|---|
| Intervals getting slower | Add 1 more rest day, reduce reps by 2, don't reduce pace |
| Easy runs feel hard | You're running too fast on easy days - slow down by 30 sec/km |
| Missed sessions (illness/life) | Don't try to "make up" missed runs - just continue from where you left off |
| Time trial worse than expected | Repeat the current phase 1 extra week before moving on |
| General fatigue, heavy legs | Take a full 3-day rest, then restart the week |
| Week 5 TT Result | Action |
|---|---|
| Sub 6:30 | ✅ On track - continue Phase 2 as planned |
| 6:30 - 6:45 | ⚠️ Slightly behind - extend Phase 2 by 1 week |
| Over 6:45 | ❌ Repeat Phase 1 for 2 more weeks before moving on |
| Week 9 TT Result | Action |
|---|---|
| Sub 6:00 | ✅ On track for sub-5:30 by rally |
| 6:00 - 6:20 | ⚠️ Need to sharpen - add 1 extra speed session per week |
| Over 6:20 | ❌ Focus entirely on intervals + speed, cut long runs |
| Lap | Target Split |
|---|---|
| Lap 1 | 80-82 sec (controlled start) |
| Lap 2 | 82-84 sec (settle into pace) |
| Lap 3 | 83-85 sec (hold on) |
| Lap 4 | 78-80 sec (empty the tank) |
Create an emergency catch-up plan if I'm behind
21nov 2026
python3 -c " from datetime import date start = date(2026, 8, 12) rally = date(2026, 11, 21) delta = rally - start weeks = delta.days // 7 days = delta.days % 7 print(f'Days to rally: {delta.days}') print(f'Full weeks: {weeks} weeks and {days} days') "
~/running-plan/generate_emergency.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.units import mm
from reportlab.lib.styles import ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle,
HRFlowable, PageBreak, KeepTogether
)
OUTPUT = "/tmp/workspace/running-plan/emergency_catchup_plan.pdf"
W, H = A4
PAGE_W = W - 26*mm
# ── Colours ───────────────────────────────────────────────────────────────────
C_BG = colors.HexColor("#0D0D1A")
C_DARK = colors.HexColor("#1A1A2E")
C_CARD = colors.HexColor("#16213E")
C_ACCENT = colors.HexColor("#E94560")
C_GOLD = colors.HexColor("#F5A623")
C_GREEN = colors.HexColor("#27AE60")
C_BLUE = colors.HexColor("#1A6FA8")
C_RED = colors.HexColor("#C0392B")
C_LIGHT = colors.HexColor("#ECF0F1")
C_MID = colors.HexColor("#7F8C8D")
C_WHITE = colors.white
C_EASY = colors.HexColor("#D5F5E3")
C_HARD = colors.HexColor("#FADBD8")
C_INTER = colors.HexColor("#D6EAF8")
C_REST = colors.HexColor("#F2F3F4")
C_TEMPO = colors.HexColor("#FDEBD0")
C_WARN = colors.HexColor("#FFF3CD")
C_TRIG = colors.HexColor("#1A0A00")
def S(name, **kw):
return ParagraphStyle(name, **kw)
title_s = S("T", fontSize=22, textColor=C_WHITE, fontName="Helvetica-Bold", alignment=TA_CENTER, leading=26)
sub_s = S("Su", fontSize=10, textColor=C_GOLD, fontName="Helvetica", alignment=TA_CENTER)
alert_s = S("Al", fontSize=11, textColor=C_WHITE, fontName="Helvetica-Bold", alignment=TA_CENTER)
h2_s = S("H2", fontSize=11, textColor=C_ACCENT, fontName="Helvetica-Bold", spaceAfter=2)
body_s = S("B", fontSize=9, textColor=C_DARK, fontName="Helvetica", leading=13)
cell_s = S("C", fontSize=8, textColor=C_DARK, fontName="Helvetica", leading=10)
cell_b = S("Cb", fontSize=8, textColor=C_DARK, fontName="Helvetica-Bold", leading=10)
cell_w = S("Cw", fontSize=8, textColor=C_WHITE, fontName="Helvetica", leading=10)
cell_bw = S("Cbw",fontSize=8, textColor=C_WHITE, fontName="Helvetica-Bold", leading=10, alignment=TA_CENTER)
note_s = S("N", fontSize=7.5,textColor=C_MID, fontName="Helvetica-Oblique", alignment=TA_CENTER, leading=10)
rule_s = S("R", fontSize=9, textColor=C_WHITE, fontName="Helvetica-Bold", leading=12)
rule_d = S("Rd", fontSize=8.5,textColor=C_LIGHT, fontName="Helvetica", leading=11)
warn_s = S("W", fontSize=8.5,textColor=colors.HexColor("#7D6608"), fontName="Helvetica", leading=11)
def banner(text, bg=C_CARD, fg=C_ACCENT, size=11, pad=6):
st = S("bn", fontSize=size, textColor=fg, fontName="Helvetica-Bold", alignment=TA_CENTER)
t = Table([[Paragraph(text, st)]], colWidths=[PAGE_W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), bg),
("TOPPADDING", (0,0),(-1,-1), pad),
("BOTTOMPADDING", (0,0),(-1,-1), pad),
]))
return t
def week_block(week_num, date_range, tag, sessions, note="", tag_color=C_ACCENT):
"""sessions: list of (day, session_label, detail, bg_color)"""
# Header
hdr = Table([[
Paragraph(f"WEEK {week_num}", S("wh", fontSize=9, textColor=C_WHITE, fontName="Helvetica-Bold")),
Paragraph(date_range, S("wd", fontSize=8, textColor=C_LIGHT, fontName="Helvetica")),
Paragraph(tag, S("wt", fontSize=8, textColor=C_WHITE, fontName="Helvetica-Bold", alignment=TA_CENTER)),
Paragraph(note, S("wn", fontSize=7.5, textColor=C_GOLD, fontName="Helvetica-Oblique")),
]], colWidths=[22*mm, 38*mm, 35*mm, PAGE_W-95*mm])
hdr.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), tag_color),
("TOPPADDING", (0,0),(-1,-1), 4),
("BOTTOMPADDING", (0,0),(-1,-1), 4),
("LEFTPADDING", (0,0),(-1,-1), 6),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
("BACKGROUND", (2,0),(2,0), colors.HexColor("#00000033")),
]))
# Sessions
rows = []
for day, label, detail, bg in sessions:
rows.append([
Paragraph(day, S("dy", fontSize=8, textColor=C_DARK, fontName="Helvetica-Bold")),
Paragraph(label, S("sl", fontSize=8, textColor=C_DARK, fontName="Helvetica-Bold", leading=10)),
Paragraph(detail, S("sd", fontSize=7.5, textColor=colors.HexColor("#2C3E50"), fontName="Helvetica", leading=10)),
])
col_w = [12*mm, 45*mm, PAGE_W - 57*mm]
body = Table(rows, colWidths=col_w)
ts = TableStyle([
("GRID", (0,0),(-1,-1), 0.3, C_MID),
("TOPPADDING", (0,0),(-1,-1), 3),
("BOTTOMPADDING", (0,0),(-1,-1), 3),
("LEFTPADDING", (0,0),(-1,-1), 5),
("VALIGN", (0,0),(-1,-1), "TOP"),
])
for i, (day, label, detail, bg) in enumerate(sessions):
ts.add("BACKGROUND", (0,i),(2,i), bg)
body.setStyle(ts)
return KeepTogether([hdr, body, Spacer(1, 3*mm)])
# ── Day colours ───────────────────────────────────────────────────────────────
E = C_EASY
I = C_INTER
H = C_HARD
R = C_REST
T = C_TEMPO
PT= colors.HexColor("#E8DAEF") # purple/light for PT
# ── Date ranges (starting Aug 12 2026) ───────────────────────────────────────
from datetime import date, timedelta
start = date(2026, 8, 12)
def dr(week_num):
ws = start + timedelta(weeks=week_num-1)
we = ws + timedelta(days=6)
return f"{ws.strftime('%d %b')} – {we.strftime('%d %b')}"
# ── Build story ───────────────────────────────────────────────────────────────
story = []
# ── COVER ─────────────────────────────────────────────────────────────────────
cover = Table([[
Paragraph("EMERGENCY CATCH-UP PLAN", title_s),
Paragraph("Territorial Army Open Rally | 21 November 2026", sub_s),
Paragraph("14 Weeks 3 Days | Current: 7:00 | Target: Sub 5:30",
S("cv", fontSize=10, textColor=C_MID, fontName="Helvetica", alignment=TA_CENTER)),
]], colWidths=[PAGE_W])
cover.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), C_BG),
("TOPPADDING", (0,0),(-1,-1), 10),
("BOTTOMPADDING", (0,0),(-1,-1), 10),
("ALIGN", (0,0),(-1,-1), "CENTER"),
]))
story.append(cover)
story.append(Spacer(1, 4*mm))
# ── RALLY REQUIREMENTS ────────────────────────────────────────────────────────
story.append(banner("TERRITORIAL ARMY RALLY - PHYSICAL REQUIREMENTS", C_RED, C_WHITE, 10))
req_data = [
[Paragraph("Event", cell_bw), Paragraph("Standard", cell_bw), Paragraph("Your Gap", cell_bw), Paragraph("Priority", cell_bw)],
[Paragraph("1600m Run", cell_b), Paragraph("Sub 5:30", cell_s), Paragraph("Need 1:30 faster", cell_s), Paragraph("🔴 CRITICAL", S("p", fontSize=8, textColor=C_RED, fontName="Helvetica-Bold", leading=10))],
[Paragraph("Pull-ups", cell_b), Paragraph("Min 6 reps", cell_s), Paragraph("Build from now", cell_s), Paragraph("🟠 HIGH", S("p2",fontSize=8, textColor=C_GOLD, fontName="Helvetica-Bold", leading=10))],
[Paragraph("9-ft Ditch Jump",cell_b),Paragraph("Clear it", cell_s), Paragraph("Leg power needed", cell_s),Paragraph("🟡 MEDIUM", S("p3",fontSize=8, textColor=colors.HexColor("#7D6608"), fontName="Helvetica-Bold", leading=10))],
[Paragraph("Zig-zag Balance",cell_b),Paragraph("Complete", cell_s), Paragraph("Core stability", cell_s), Paragraph("🟢 LOW", S("p4",fontSize=8, textColor=C_GREEN, fontName="Helvetica-Bold", leading=10))],
]
req_tbl = Table(req_data, colWidths=[40*mm, 30*mm, 50*mm, PAGE_W-120*mm])
req_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), C_RED),
("ROWBACKGROUNDS",(0,1),(-1,-1), [C_HARD, C_LIGHT, C_WARN, C_EASY]),
("GRID", (0,0),(-1,-1), 0.4, C_MID),
("TOPPADDING", (0,0),(-1,-1), 4),
("BOTTOMPADDING", (0,0),(-1,-1), 4),
("LEFTPADDING", (0,0),(-1,-1), 5),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
]))
story.append(Spacer(1, 2*mm))
story.append(req_tbl)
story.append(Spacer(1, 4*mm))
# ── 400m PACE TARGET ──────────────────────────────────────────────────────────
story.append(banner("SUB 5:30 RACE SPLIT TARGETS (Each 400m Lap)", C_DARK, C_GOLD, 10))
lap_data = [
[Paragraph("Lap", cell_bw), Paragraph("Target Split", cell_bw), Paragraph("Cumulative", cell_bw), Paragraph("Strategy", cell_bw)],
[Paragraph("Lap 1 (0-400m)", cell_b), Paragraph("80 sec", cell_s), Paragraph("1:20", cell_s), Paragraph("Controlled start. Don't sprint.", cell_s)],
[Paragraph("Lap 2 (400-800m)",cell_b), Paragraph("82 sec", cell_s), Paragraph("2:42", cell_s), Paragraph("Settle into rhythm. Relax arms.", cell_s)],
[Paragraph("Lap 3 (800-1200m)",cell_b),Paragraph("83 sec", cell_s), Paragraph("4:05", cell_s), Paragraph("This lap hurts. Hold pace. Breathe.", cell_s)],
[Paragraph("Lap 4 (1200-1600m)",cell_b),Paragraph("79 sec",cell_s), Paragraph("5:24", cell_s), Paragraph("Empty the tank. Lean forward. Sprint.", cell_s)],
]
lap_tbl = Table(lap_data, colWidths=[42*mm, 28*mm, 28*mm, PAGE_W-98*mm])
lap_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), C_DARK),
("ROWBACKGROUNDS",(0,1),(-1,-1), [C_EASY, C_INTER, C_TEMPO, C_HARD]),
("GRID", (0,0),(-1,-1), 0.4, C_MID),
("TOPPADDING", (0,0),(-1,-1), 4),
("BOTTOMPADDING", (0,0),(-1,-1), 4),
("LEFTPADDING", (0,0),(-1,-1), 5),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
]))
story.append(Spacer(1, 2*mm))
story.append(lap_tbl)
story.append(Spacer(1, 4*mm))
# ── TRIGGER SYSTEM ────────────────────────────────────────────────────────────
story.append(banner("CATCH-UP TRIGGER SYSTEM - When to Activate Emergency Mode", C_TRIG, C_GOLD, 10))
story.append(Spacer(1, 2*mm))
trig_data = [
[Paragraph("Check Point", cell_bw), Paragraph("Time Trial Result", cell_bw), Paragraph("Status", cell_bw), Paragraph("Action", cell_bw)],
[Paragraph("Week 5 TT\n(mid Sep)", cell_b), Paragraph("Sub 6:20", cell_s), Paragraph("✅ On Track", S("ok", fontSize=8, textColor=C_GREEN, fontName="Helvetica-Bold", leading=10)), Paragraph("Continue Phase 2 as planned", cell_s)],
[Paragraph("Week 5 TT", cell_b), Paragraph("6:20 - 6:40", cell_s), Paragraph("⚠️ Slight Delay", S("sl2",fontSize=8,textColor=C_GOLD, fontName="Helvetica-Bold",leading=10)), Paragraph("Repeat Phase 2 Week 1 before moving on", cell_s)],
[Paragraph("Week 5 TT", cell_b), Paragraph("Over 6:40", cell_s), Paragraph("🔴 Emergency", S("em", fontSize=8, textColor=C_RED, fontName="Helvetica-Bold", leading=10)), Paragraph("Switch to Emergency Protocol NOW", cell_s)],
[Paragraph("Week 9 TT\n(mid Oct)", cell_b), Paragraph("Sub 5:55", cell_s), Paragraph("✅ On Track", S("ok2",fontSize=8,textColor=C_GREEN,fontName="Helvetica-Bold",leading=10)), Paragraph("Normal taper into rally", cell_s)],
[Paragraph("Week 9 TT", cell_b), Paragraph("5:55 - 6:15", cell_s), Paragraph("⚠️ Slight Delay", S("sl3",fontSize=8,textColor=C_GOLD, fontName="Helvetica-Bold",leading=10)), Paragraph("Add 2 extra interval sessions in Wk 10-11", cell_s)],
[Paragraph("Week 9 TT", cell_b), Paragraph("Over 6:15", cell_s), Paragraph("🔴 Emergency", S("em2",fontSize=8,textColor=C_RED, fontName="Helvetica-Bold",leading=10)), Paragraph("Full Emergency Protocol - see Page 2", cell_s)],
]
trig_tbl = Table(trig_data, colWidths=[30*mm, 32*mm, 30*mm, PAGE_W-92*mm])
trig_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), C_DARK),
("ROWBACKGROUNDS",(0,1),(-1,-1), [C_EASY, C_WARN, C_HARD, C_EASY, C_WARN, C_HARD]),
("GRID", (0,0),(-1,-1), 0.4, C_MID),
("TOPPADDING", (0,0),(-1,-1), 4),
("BOTTOMPADDING", (0,0),(-1,-1), 4),
("LEFTPADDING", (0,0),(-1,-1), 5),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
]))
story.append(trig_tbl)
story.append(PageBreak())
# ── PAGE 2: 14-WEEK SCHEDULE ──────────────────────────────────────────────────
story.append(banner("14-WEEK RALLY COUNTDOWN SCHEDULE", C_BG, C_WHITE, 12, 8))
story.append(Spacer(1, 3*mm))
# Phase banners
def phase_hdr(text, sub, bg):
t = Table([[
Paragraph(text, S("ph", fontSize=11, textColor=C_WHITE, fontName="Helvetica-Bold", alignment=TA_CENTER)),
Paragraph(sub, S("pd", fontSize=8, textColor=C_LIGHT, fontName="Helvetica", alignment=TA_CENTER)),
]], colWidths=[PAGE_W])
t.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), bg),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING", (0,0),(-1,-1), 5),
]))
return t
# ── PHASE 1: BASE (Weeks 1-4) ─────────────────────────────────────────────────
story.append(phase_hdr("PHASE 1: AEROBIC BASE (Weeks 1-4)", "Build the engine. All runs easy. Intervals at current pace.", C_GREEN))
story.append(Spacer(1,2*mm))
w1_sessions = [
("MON", "Long Run", "35 min @ 6:30-7:00/km. Conversational pace.", E),
("TUE", "Recovery + PT", "20 min easy jog. Then: 3x10 squats, 3x10 lunges, 3x10 calf raises, 3x plank 30s.", R),
("WED", "Intervals", "6 x 400m @ 1:45 each. 90 sec jog rest between.", I),
("THU", "Recovery Run", "20 min @ 7:00/km. Very easy.", R),
("FRI", "Speed", "8 x 200m @ 52 sec each. 60 sec rest. OR 6 hill sprints (40m).", H),
("SAT", "Easy + Pull-ups","30 min easy + 3 sets pull-ups to failure (min 3).", E),
("SUN", "REST", "Full rest. Walk only.", R),
]
story.append(week_block(1, dr(1), "BASE BUILDING", w1_sessions, "Start conservative.", C_GREEN))
w2_sessions = [
("MON", "Long Run", "40 min @ 6:30/km.", E),
("TUE", "Recovery + PT", "20 min easy. Squats 3x12, Lunges 3x12, Calf raises 4x15, Plank 3x35s.", R),
("WED", "Intervals", "6 x 400m @ 1:43. 90 sec jog rest.", I),
("THU", "Recovery Run", "20 min easy.", R),
("FRI", "Hills", "6 x 40m hill sprints. Walk back = full rest. Explosive drive.", H),
("SAT", "Easy + Pull-ups","30 min easy + 3 sets pull-ups + 3x15 push-ups.", E),
("SUN", "REST", "Full rest.", R),
]
story.append(week_block(2, dr(2), "BASE BUILDING", w2_sessions, "", C_GREEN))
w3_sessions = [
("MON", "Long Run", "40 min @ 6:20/km.", E),
("TUE", "Recovery + PT", "25 min easy. Squats 3x15, Bulgarian split squat 3x8/leg, Calf raises 4x20, Plank 3x40s.", R),
("WED", "Intervals", "8 x 400m @ 1:42. 90 sec jog rest. (Toughest Wed so far)", I),
("THU", "Recovery Run", "20 min easy.", R),
("FRI", "Speed", "10 x 200m @ 50 sec. 60 sec rest.", H),
("SAT", "Easy + Pull-ups","30 min easy + 4 sets pull-ups + push-ups 3x15.", E),
("SUN", "REST", "Full rest.", R),
]
story.append(week_block(3, dr(3), "BASE BUILDING", w3_sessions, "", C_GREEN))
w4_sessions = [
("MON", "Easy Run", "30 min @ 6:30/km. DELOAD - lighter week.", E),
("TUE", "Recovery + PT", "20 min easy. Light PT: 2x10 squats, 2x plank 30s.", R),
("WED", "Intervals", "5 x 400m @ 1:42. 2 min rest. (Deload: fewer reps)", I),
("THU", "REST", "Full rest.", R),
("FRI", "Speed", "6 x 200m @ 50 sec. 75 sec rest.", H),
("SAT", "Easy + Pull-ups","25 min easy + 3 sets pull-ups.", E),
("SUN", "REST", "Full rest. Body adapts this week.", R),
]
story.append(week_block(4, dr(4), "DELOAD WEEK", w4_sessions, "Cut volume 30%. Recovery = gains.", C_BLUE))
# ── PHASE 2: SPEED DEV (Weeks 5-8) ───────────────────────────────────────────
story.append(phase_hdr("PHASE 2: SPEED DEVELOPMENT (Weeks 5-8)", "Faster reps. Introduce 600m. First time trial Week 5.", C_GOLD))
story.append(Spacer(1,2*mm))
w5_sessions = [
("MON", "Easy Run", "35 min @ 6:00-6:30/km.", E),
("TUE", "Recovery + PT", "20 min easy. Squats 3x12, Split squat 3x10/leg, Calf raises 4x20, Side plank 3x30s.", R),
("WED", "TIME TRIAL", "1600m solo time trial. Warm-up 10 min easy. Run full effort. Cool down 10 min. NOTE YOUR TIME.", H),
("THU", "Recovery Run", "20 min very easy. Legs recovering from TT.", R),
("FRI", "Speed", "6 x 300m @ 1:12. 2 min rest. (New distance - push pace)", H),
("SAT", "Easy + Pull-ups","35 min easy + 4 sets pull-ups + push-ups 3x18.", E),
("SUN", "REST", "Full rest.", R),
]
story.append(week_block(5, dr(5), "TIME TRIAL WK", w5_sessions, "TARGET: Sub 6:20 on TT.", C_ACCENT))
w6_sessions = [
("MON", "Long Run", "40 min @ 6:00/km.", E),
("TUE", "Recovery + PT", "25 min easy. Full strength: split squat 3x10, RDL 3x12, calf 4x20, plank 3x45s.", R),
("WED", "Intervals", "6 x 400m @ 1:38. 2 min rest. FASTER than Phase 1.", I),
("THU", "Recovery Run", "20 min easy.", R),
("FRI", "Hills", "8 x 40m hill sprints. Explosive. Walk back rest.", H),
("SAT", "Easy + Pull-ups","30 min easy + 4 sets pull-ups + push-ups 3x20.", E),
("SUN", "REST", "Full rest.", R),
]
story.append(week_block(6, dr(6), "SPEED DEV", w6_sessions, "", C_GOLD))
w7_sessions = [
("MON", "Long Run", "45 min @ 5:55/km.", E),
("TUE", "Recovery + PT", "25 min easy. Split squat 3x12, jump squats 3x6, calf 4x20, dead bug 3x10.", R),
("WED", "Intervals", "5 x 600m @ 2:35 each. 2.5 min rest. (First 600s - hold pace!)", I),
("THU", "Recovery Run", "20 min easy.", R),
("FRI", "Speed", "6 x 300m @ 1:10. 2 min rest.", H),
("SAT", "Easy + Pull-ups","30 min easy + strides 6x80m + 5 sets pull-ups.", E),
("SUN", "REST", "Full rest.", R),
]
story.append(week_block(7, dr(7), "SPEED DEV", w7_sessions, "", C_GOLD))
w8_sessions = [
("MON", "Easy Run", "30 min @ 6:20/km. DELOAD.", E),
("TUE", "Recovery + PT", "20 min easy. Light PT only: 2x10 squats, 2x plank.", R),
("WED", "Intervals", "4 x 600m @ 2:32. 2.5 min rest. (Deload: fewer reps)", I),
("THU", "REST", "Full rest.", R),
("FRI", "Speed", "5 x 200m @ 47 sec. 90 sec rest.", H),
("SAT", "Easy + Pull-ups","25 min easy + 4 sets pull-ups.", E),
("SUN", "REST", "Full rest. Critical recovery.", R),
]
story.append(week_block(8, dr(8), "DELOAD WEEK", w8_sessions, "Body adapts. Don't skip rest.", C_BLUE))
story.append(PageBreak())
# ── PHASE 3: RACE-SPECIFIC (Weeks 9-12) ──────────────────────────────────────
story.append(phase_hdr("PHASE 3: RACE-SPECIFIC (Weeks 9-12)", "Near goal pace. 800m reps. Second time trial Week 9.", C_ACCENT))
story.append(Spacer(1,2*mm))
w9_sessions = [
("MON", "Easy Run", "35 min @ 5:50/km.", E),
("TUE", "Recovery + PT", "20 min easy. Heavy PT: split squat 4x10, jump squats 4x6, calf 4x20, plank 3x50s.", R),
("WED", "TIME TRIAL", "1600m solo TT. Warm-up 10 min. Full effort. TARGET: Sub 5:55. Note exact time.", H),
("THU", "Recovery Run", "20 min very easy. Light jog only.", R),
("FRI", "Intervals", "4 x 800m @ 3:20 each. 3 min full rest. Race pace effort.", I),
("SAT", "Easy + Pull-ups","30 min easy + strides 6x80m + 5 sets pull-ups.", E),
("SUN", "REST", "Full rest.", R),
]
story.append(week_block(9, dr(9), "TIME TRIAL WK", w9_sessions, "TARGET: Sub 5:55 on TT.", C_ACCENT))
w10_sessions = [
("MON", "Long Run", "40 min @ 5:45/km. Peak aerobic session.", E),
("TUE", "Recovery + PT", "25 min easy. Full PT: split squat 4x10, push-ups 4x20, pull-ups 5 sets, plank 3x55s.", R),
("WED", "Intervals", "6 x 400m @ 1:30. 2 min rest. Near goal race pace.", I),
("THU", "Recovery Run", "20 min easy.", R),
("FRI", "Tempo", "3 x 1000m @ 4:35/km pace. 2.5 min rest. Sustained effort.", T),
("SAT", "Easy + Pull-ups","30 min easy + 6 strides + 5 sets pull-ups.", E),
("SUN", "REST", "Full rest.", R),
]
story.append(week_block(10, dr(10), "PEAK WEEK", w10_sessions, "Hardest week of plan.", C_RED))
w11_sessions = [
("MON", "Easy Run", "30 min @ 6:00/km. Sharpen, don't fatigue.", E),
("TUE", "Recovery + PT", "20 min easy. PT: split squat 3x8, explosive push-ups 3x10, pull-ups 5 sets.", R),
("WED", "Intervals", "8 x 300m @ 1:07 each. 2.5 min full rest. Short, sharp, fast.", I),
("THU", "Recovery Run", "20 min very easy.", R),
("FRI", "Speed", "4 x 400m @ 1:28. 3 min full rest. This is race pace.", H),
("SAT", "Easy + Pull-ups","25 min easy + strides + 5 sets pull-ups.", E),
("SUN", "REST", "Full rest.", R),
]
story.append(week_block(11, dr(11), "SHARPEN", w11_sessions, "", C_ACCENT))
# ── PHASE 4: TAPER (Weeks 12-14) ─────────────────────────────────────────────
story.append(phase_hdr("PHASE 4: TAPER (Weeks 12-14 + Rally Day)", "Cut volume. Keep sharpness. Arrive fresh on rally day.", C_BLUE))
story.append(Spacer(1,2*mm))
w12_sessions = [
("MON", "Easy Run", "25 min @ 6:20/km. Feel light.", E),
("TUE", "Recovery + PT", "15 min easy. Light PT only: 2x10 squats, 3 sets pull-ups.", R),
("WED", "Sharpener", "5 x 400m @ 1:28. 3 min rest. Keep the feel of fast.", I),
("THU", "REST", "Full rest. Stay off feet.", R),
("FRI", "Strides Only", "15 min easy + 5 x 80m strides. Feel fast, don't tire.", E),
("SAT", "Easy + Pull-ups","20 min easy + 4 sets pull-ups. Body is resting.", E),
("SUN", "REST", "Full rest.", R),
]
story.append(week_block(12, dr(12), "TAPER", w12_sessions, "Volume drops 40%. Keep race feel.", C_BLUE))
w13_sessions = [
("MON", "Easy Run", "20 min @ 6:30/km. Very light.", E),
("TUE", "Recovery + PT", "15 min easy. 3 sets pull-ups only.", R),
("WED", "Race Rehearsal", "4 x 400m @ 1:22 (goal race pace). 3 min full rest. Run EXACTLY how you'll race.", H),
("THU", "REST", "Full rest.", R),
("FRI", "Strides", "10 min easy + 4 x 80m strides. Legs should feel springy.", E),
("SAT", "Easy Walk", "20 min easy walk only. Stay active, not tired.", R),
("SUN", "REST", "Full rest. Visualise the race.", R),
]
story.append(week_block(13, dr(13), "FINAL TAPER", w13_sessions, "Legs must feel fresh by Thursday.", C_BLUE))
# Week 14 (partial - only 3 days to rally Nov 21)
w14_sessions = [
("MON", "Easy Jog", "15 min very easy. Shake out legs. 3 x 80m strides.", E),
("TUE", "Complete REST", "No running. Sleep well. Eat properly. Hydrate.", R),
("WED", "RALLY DAY", "Nov 19 prep: Light walk only. Sleep early. Pack kit.", R),
("THU", "RALLY DAY -2", "Nov 20: Eat carbs. Rest fully. Visualise 4 laps.", R),
("FRI", "RALLY DAY -1", "Nov 20: Light 10 min jog + 3 strides. Stay loose.", E),
("SAT", "RALLY DAY", "21 NOV: Warm up 15 min. 4 x 80m strides. RACE. Sub 5:30!", H),
("SUN", "-", "-", R),
]
story.append(week_block(14, "10 Nov – 21 Nov", "RALLY WEEK", w14_sessions, "RACE DAY: 21 NOV 2026", C_RED))
story.append(PageBreak())
# ── EMERGENCY PROTOCOL ────────────────────────────────────────────────────────
story.append(banner("EMERGENCY PROTOCOL - Activate If Behind After Week 5 TT", C_RED, C_WHITE, 11, 7))
story.append(Spacer(1, 2*mm))
emerg_note = Paragraph(
"If your Week 5 TT is over 6:40 OR Week 9 TT is over 6:15, drop this plan and follow the Emergency Protocol below for the remaining weeks until rally.",
S("en", fontSize=8.5, textColor=C_RED, fontName="Helvetica-Bold", leading=12)
)
story.append(emerg_note)
story.append(Spacer(1, 2*mm))
# Emergency weekly template
em_sessions = [
("MON", "Short Easy Run", "25 min @ 6:30/km. No more. Protect recovery.", E),
("TUE", "Intervals A", "6 x 400m @ TARGET pace (1:22). 2 min rest. FULL effort.", I),
("WED", "REST", "Complete rest. Legs must recover for Thursday.", R),
("THU", "Intervals B", "8 x 200m @ 40 sec. 75 sec rest. Pure speed.", H),
("FRI", "REST", "Complete rest.", R),
("SAT", "Race Sim", "2 x 800m @ 2:45 each. 4 min full rest. Simulate race effort.", I),
("SUN", "REST", "Full rest.", R),
]
em_tbl_hdr = Table([[
Paragraph("EMERGENCY WEEKLY TEMPLATE", S("eht", fontSize=10, textColor=C_WHITE, fontName="Helvetica-Bold", alignment=TA_CENTER)),
Paragraph("Repeat this structure every week until rally. Cut all long runs.", S("ehd", fontSize=8, textColor=C_LIGHT, fontName="Helvetica", alignment=TA_CENTER)),
]], colWidths=[PAGE_W])
em_tbl_hdr.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,-1), C_RED),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING", (0,0),(-1,-1), 5),
]))
story.append(em_tbl_hdr)
em_rows = []
for day, label, detail, bg in em_sessions:
em_rows.append([
Paragraph(day, S("ed", fontSize=8, textColor=C_DARK, fontName="Helvetica-Bold")),
Paragraph(label, S("el", fontSize=8, textColor=C_DARK, fontName="Helvetica-Bold", leading=10)),
Paragraph(detail, S("eds",fontSize=7.5,textColor=colors.HexColor("#2C3E50"), fontName="Helvetica", leading=10)),
])
em_body = Table(em_rows, colWidths=[12*mm, 40*mm, PAGE_W-52*mm])
em_ts = TableStyle([
("GRID", (0,0),(-1,-1), 0.3, C_MID),
("TOPPADDING", (0,0),(-1,-1), 3),
("BOTTOMPADDING",(0,0),(-1,-1), 3),
("LEFTPADDING", (0,0),(-1,-1), 5),
("VALIGN", (0,0),(-1,-1), "TOP"),
])
for i, (day, label, detail, bg) in enumerate(em_sessions):
em_ts.add("BACKGROUND", (0,i),(2,i), bg)
em_body.setStyle(em_ts)
story.append(em_body)
story.append(Spacer(1, 4*mm))
# ── PROGRESS TRACKER ─────────────────────────────────────────────────────────
story.append(banner("PROGRESS TRACKER - Fill In After Each Time Trial", C_DARK, C_GOLD, 10))
story.append(Spacer(1, 2*mm))
track_data = [
[Paragraph("Check Point", cell_bw), Paragraph("Date", cell_bw), Paragraph("Target", cell_bw),
Paragraph("Your Time", cell_bw), Paragraph("Status", cell_bw)],
[Paragraph("Baseline", cell_b), Paragraph("12 Aug", cell_s), Paragraph("7:00", cell_s), Paragraph("7:00", cell_s), Paragraph("Start", cell_s)],
[Paragraph("Week 5 TT", cell_b), Paragraph("~12 Sep", cell_s), Paragraph("Sub 6:20",cell_s), Paragraph("________", cell_s), Paragraph("________", cell_s)],
[Paragraph("Week 9 TT", cell_b), Paragraph("~9 Oct", cell_s), Paragraph("Sub 5:55",cell_s), Paragraph("________", cell_s), Paragraph("________", cell_s)],
[Paragraph("RALLY DAY", cell_b), Paragraph("21 Nov", cell_s), Paragraph("Sub 5:30",cell_s), Paragraph("________", cell_s), Paragraph("________", cell_s)],
]
track_tbl = Table(track_data, colWidths=[32*mm, 28*mm, 30*mm, 32*mm, PAGE_W-122*mm])
track_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0),(-1,0), C_DARK),
("ROWBACKGROUNDS",(0,1),(-1,-1), [C_LIGHT, C_INTER, C_TEMPO, C_HARD]),
("GRID", (0,0),(-1,-1), 0.5, C_MID),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING", (0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 6),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
]))
story.append(track_tbl)
story.append(Spacer(1, 4*mm))
# ── GOLDEN RULES ─────────────────────────────────────────────────────────────
story.append(banner("5 NON-NEGOTIABLE RULES FOR RALLY SUCCESS", C_BG, C_WHITE, 10))
story.append(Spacer(1, 2*mm))
rules = [
("1. Wednesday intervals are sacred",
"Miss any session except Wednesday. Never skip intervals - this is where your 5:30 comes from."),
("2. Easy runs stay EASY",
"If your easy run feels hard, you are running too fast. Slow down by 30 sec/km. This is not laziness - it is recovery."),
("3. Never add extra hard sessions",
"When behind, the instinct is to run more. Don't. Quality over quantity always wins."),
("4. Check morning HR daily",
"Before getting up: if HR is 7+ BPM above normal, take an extra rest day. No exceptions."),
("5. The last 10 days decide nothing",
"Fitness is built in Weeks 1-11. Weeks 12-14 are for showing up fresh. Rest is not weakness."),
]
for title, detail in rules:
r_tbl = Table([[
Paragraph(title, rule_s),
Paragraph(detail, rule_d),
]], colWidths=[60*mm, PAGE_W-60*mm])
r_tbl.setStyle(TableStyle([
("BACKGROUND", (0,0),(0,0), C_DARK),
("BACKGROUND", (1,0),(1,0), C_CARD),
("TOPPADDING", (0,0),(-1,-1), 5),
("BOTTOMPADDING", (0,0),(-1,-1), 5),
("LEFTPADDING", (0,0),(-1,-1), 7),
("VALIGN", (0,0),(-1,-1), "MIDDLE"),
("LINEBELOW", (0,0),(-1,-1), 0.3, colors.HexColor("#2C3E6B")),
]))
story.append(r_tbl)
story.append(Spacer(1, 4*mm))
story.append(Paragraph(
"Orris Training Assistant | Rally: 21 November 2026 | Target: Sub 5:30 | 14 weeks 3 days remaining",
S("ft", fontSize=7, textColor=C_MID, fontName="Helvetica-Oblique", alignment=TA_CENTER)
))
doc = SimpleDocTemplate(
OUTPUT,
pagesize=A4,
rightMargin=13*mm, leftMargin=13*mm,
topMargin=10*mm, bottomMargin=10*mm,
title="Emergency Catch-Up Plan - Territorial Army Rally",
)
doc.build(story)
print(f"PDF saved: {OUTPUT}")
cd /tmp/workspace/running-plan && python generate_emergency.py 2>&1
ls -lh /tmp/workspace/running-plan/
emergency catchup plan
PDF Document · PDF
| Date | Event | Target |
|---|---|---|
| ~12 Sep | Week 5 Time Trial | Sub 6:20 |
| ~9 Oct | Week 9 Time Trial | Sub 5:55 |
| 21 Nov | Rally Day | Sub 5:30 |
3 and 4
What do you mean by 3 and 4?
What type of food do you eat?
| Nutrient | Why | Daily Target |
|---|---|---|
| Carbs | Fuel for intervals and speed work | 55-60% of calories |
| Protein | Muscle repair after hard sessions | 1.4-1.6g per kg body weight |
| Fats | Hormone production, joint health | 25-30% of calories |
| Water | Performance drops 5% when even slightly dehydrated | 3-4 litres/day |
| Item | Why Buy It | Approx Cost |
|---|---|---|
| Eggs (dozen) | Best cheap protein | Low |
| Dal / lentils (500g) | Protein + carbs | Very low |
| Bananas (bunch) | Pre/post run fuel | Very low |
| Oats (500g) | Breakfast carbs, lasts weeks | Low |
| Peanuts / peanut butter | Healthy fats + protein | Low |
| Milk (1L/day if possible) | Protein + calcium | Moderate |
| Rice / atta (flour) | Base carbs | Very low |
| Seasonal vegetables | Vitamins, minerals | Very low |
| Chana (chickpeas) | Snack protein | Very low |
| Day | Adjust How |
|---|---|
| Hard session (Wed/Fri) | Eat more carbs - extra roti/rice at lunch |
| Easy / recovery day | Normal portions, slightly less carbs |
| Rest day (Sunday) | Slightly less food overall, same protein |
| Day before time trial | Eat more carbs the evening before - rice/roti heavy dinner |
I will do the running in the evening
| Time | Meal | What to Eat |
|---|---|---|
| 7:00-8:00 AM | Breakfast | Oats + milk + banana OR 2 eggs + 2 rotis. Full meal. |
| 11:00-12:00 PM | Lunch | Rice/roti + dal + vegetable + curd. Biggest meal of day. |
| 3:00-4:00 PM | Pre-run snack | 1 banana + handful peanuts OR bread + peanut butter. |
| 5:00-6:00 PM | RUN | Training session |
| 6:30-7:00 PM | Post-run meal | Protein + carbs within 45 min. (Most important) |
| 8:30-9:00 PM | Dinner | Light - roti + dal/eggs + vegetables. Not too heavy. |
Morning: Full breakfast (eggs/oats)
Afternoon: Full lunch (dal + rice)
3-4 PM: Light snack (banana + peanuts)
5-6 PM: RUN
6:30 PM: Recovery meal (protein + carbs) within 45 min
8:30 PM: Light dinner
10-11 PM: Sleep (minimum 7-8 hours)
Any equipment needed
How can i build my physique with running