Standard org-habit tracks habits using fixed repeater intervals: complete the habit, and it reschedules for the next interval. This works well for habits with predictable schedules, but many real-world habits don’t fit that model:
- Exercise 5 times per week - You don’t care which 5 days, just that you hit 5 within any 7-day window
- Read 4 books per month - Finishing one book per week is fine, but so is reading two books in the first week and two in the last
- Take medication 3 times per day - The exact hours don’t matter, just the count within each 24-hour period
With standard org-habit, missing a single day shows as a “failure” in your consistency graph, even if you’re exceeding your actual goals. This can be demoralizing and doesn’t reflect how habits actually work in practice.
org-window-habit replaces this binary daily model with window-based tracking: instead of asking “did you do it today?”, it asks “have you done it enough times within this time window?”
A window habit evaluates your compliance over a rolling time window rather than a single day. You define:
- Window Duration - How far back to look when counting completions (e.g., 7 days, 1 month)
- Repetitions Required - How many completions are needed within that window (e.g., 5 times)
- Assessment Interval - How often to re-evaluate, i.e., the step size for the rolling window (e.g., daily)
Note that window duration and assessment interval serve different purposes: the window duration determines how much history counts toward your goal, while the assessment interval determines how granularly the window rolls forward. For example, with a 7-day window and 1-day assessment interval, you get a fresh evaluation each day that looks back at the previous 7 days. If the assessment interval were also 7 days, the window would jump weekly rather than rolling daily.
A practical example where these differ: suppose you want to write 8 blog posts per month, but you don’t want daily nagging - just a weekly check-in. You’d set a 1-month window duration with a 1-week assessment interval. Each week, the system evaluates whether you’re on track for your monthly goal, and the habit only appears in your agenda at weekly boundaries.
For fixed-length intervals (days, hours), assessment boundaries are anchored to your habit’s start time, not arbitrary calendar boundaries. This means:
- A habit with a 3-day assessment interval that started on Jan 10 will have periods: Jan 10-13, Jan 13-16, Jan 16-19, etc.
- Another habit with the same 3-day interval but starting Jan 11 will have different periods: Jan 11-14, Jan 14-17, Jan 17-20, etc.
This ensures consistent, predictable evaluation periods for each habit.
The library tracks your completions and calculates a conforming ratio - are you on track to meet your goal? The agenda graph shows this visually, with colors indicating your conformity status (by default, green when conforming and red when falling behind).
When you complete a habit, org-window-habit automatically reschedules it to the next date when a completion will be needed to maintain conformity, rather than using a fixed repeater interval.
You want to exercise 5 times per week. With org-window-habit:
* TODO Exercise
SCHEDULED: <2024-01-15 Mon .+1d>
:PROPERTIES:
:STYLE: habit
:OWH_CONFIG: (:window-specs ((:duration (:days 7) :repetitions 5)))
:END:
If you exercise Monday, Tuesday, Wednesday, Thursday, and Friday, you’ve met your goal for the week. Saturday and Sunday will show as “optional” - you don’t need to exercise, but you can if you want to build buffer.
If you only exercised 3 times so far this week and it’s Friday, the graph shows you’re behind and the habit appears as requiring completion.
org-window-habit is available on MELPA. With use-package:
(use-package org-window-habit
:ensure t
:demand t
:config
(org-window-habit-mode +1))Or install from git using straight.el:
(use-package org-window-habit
:demand t
:straight
(org-window-habit
:repo "colonelpanic8/org-window-habit"
:host github
:files ("org-window-habit.el"))
:config
(org-window-habit-mode +1))- Create a TODO heading with
SCHEDULEDorDEADLINEthat has any repeater (the repeater value doesn’t matter - org-window-habit uses its own rescheduling logic, but a repeater must be present) - Add
:STYLE: habitunder:PROPERTIES: - Add the
OWH_CONFIGproperty with your habit configuration - Ensure Org is logging TODO state changes for the entry.
org-window-habitreads completion history from standard Org state-change logs whether they are stored inline or inside aLOGBOOKdrawer. Settingorg-log-into-draweris optional.
The OWH_CONFIG property is the recommended way to configure window habits. It uses a single property containing all habit parameters:
* TODO Exercise
SCHEDULED: <2024-01-15 Mon .+1d>
:PROPERTIES:
:STYLE: habit
:OWH_CONFIG: (:window-specs ((:duration (:days 7) :repetitions 5)))
:END:
This defines a habit requiring 5 completions per 7-day window.
With additional options:
* TODO Exercise
SCHEDULED: <2024-01-15 Mon .+1d>
:PROPERTIES:
:STYLE: habit
:OWH_CONFIG: (:window-specs ((:duration (:days 7) :repetitions 5)) :assessment-interval (:days 1) :only-days (:monday :wednesday :friday))
:END:
Available CONFIG keys:
| Key | Required | Default | Description |
|---|---|---|---|
:window-specs | Yes | - | List of window specifications (see below) |
:assessment-interval | No | (:days 1) | How often to re-evaluate |
:reschedule-interval | No | (:days 1) | Minimum time after completion before rescheduling |
:reschedule-threshold | No | 1.0 | Conforming ratio threshold for rescheduling |
:max-reps-per-interval | No | 1 | Max completions counted per assessment interval |
:only-days | No | (all days) | Restrict to specific days (e.g., (:monday :friday)) |
:from | No | (unbounded) | Ignore completions before this date |
Window spec format:
(:duration (:days 7) :repetitions 5)
(:duration (:days 7) :repetitions 5 :value 1.0) ; with explicit weightHabits often evolve over time - you might start with 3 workouts per week and gradually increase to 5. The CONFIG property supports versioned configurations that let your habit requirements change while preserving accurate historical tracking.
Example: Increasing workout frequency
* TODO Exercise
SCHEDULED: <2024-01-15 Mon .+1d>
:PROPERTIES:
:STYLE: habit
:OWH_CONFIG: ((:window-specs ((:duration (:days 7) :repetitions 5))) (:until "2024-06-01" :window-specs ((:duration (:days 7) :repetitions 3))))
:END:
This defines:
- Current requirement: 5 times per week (active from June 1, 2024 onward)
- Previous requirement: 3 times per week (active until June 1, 2024)
Versioned config rules:
- Configs are listed in reverse temporal order (most recent first)
- The first config has no
:until(active now and forever) - Each config’s
:fromis implicitly the previous config’s:until - An explicit
:fromon a config creates a gap where the habit is inactive
With a gap (habit pause):
:OWH_CONFIG: ((:window-specs ((:duration (:days 7) :repetitions 5))) (:until "2024-06-01" :from "2024-01-01" :window-specs ((:duration (:days 7) :repetitions 3))))
This habit was inactive before January 1, 2024 (the :from on the oldest config acts like a reset time).
For backwards compatibility, you can use individual properties instead of OWH_CONFIG. See “Configuration Properties Reference” below for the full list of legacy properties and defaults.
Monthly reading example:
* TODO Read a book
SCHEDULED: <2024-01-15 Mon .+1d>
:PROPERTIES:
:STYLE: habit
:OWH_CONFIG: (:window-specs ((:duration (:months 1) :repetitions 4)))
:END:
Calendar-aligned monthly task (e.g., paying rent):
For tasks that must happen exactly once per calendar month (not a rolling 30-day window), set both the window duration and assessment interval to (:months 1). The library aligns monthly intervals to the 1st of each month:
* TODO Pay rent
SCHEDULED: <2024-01-01 Mon .+1d>
:PROPERTIES:
:STYLE: habit
:OWH_CONFIG: (:window-specs ((:duration (:months 1) :repetitions 1)) :assessment-interval (:months 1))
:END:
This evaluates once per calendar month: did you pay rent in January? In February? The window doesn’t roll daily - it jumps from month to month, aligned to calendar boundaries.
If you want a habit that simply repeats a fixed number of days after each completion - like traditional org-habit with a .+3d repeater - you can achieve this with org-window-habit:
* TODO Water plants
SCHEDULED: <2024-01-15 Mon .+1d>
:PROPERTIES:
:STYLE: habit
:OWH_CONFIG: (:window-specs ((:duration (:days 3) :repetitions 1)))
:END:
This says “I need to water plants once every 3 days.” After completing, the habit automatically reschedules to the next date when a completion will be needed - approximately 3 days out.
The key insight is that org-window-habit’s rescheduling is based on when you’ll fall out of conformity, not a fixed offset. With a 3-day window requiring 1 completion, you’ll need to complete again within 3 days of your last completion to stay conforming.
Taking medication every 8 hours:
* TODO Take medication
SCHEDULED: <2024-01-15 Mon .+1d>
:PROPERTIES:
:STYLE: habit
:OWH_CONFIG: (:window-specs ((:duration (:hours 8) :repetitions 1)) :assessment-interval (:hours 1))
:END:
Weekly task (once per week):
* TODO Review finances
SCHEDULED: <2024-01-15 Mon .+1d>
:PROPERTIES:
:STYLE: habit
:OWH_CONFIG: (:window-specs ((:duration (:days 7) :repetitions 1)))
:END:
The advantage over traditional org-habit is that you still get the visual conformity graph showing your history, and the flexibility to complete early without penalty.
For more complex requirements, use :window-specs in OWH_CONFIG to define multiple evaluation windows. The habit must satisfy all windows simultaneously.
:PROPERTIES:
:OWH_CONFIG: (:window-specs ((:duration (:days 4) :repetitions 1) (:duration (:days 6) :repetitions 2)))
:END:
This requires:
- At least 1 completion in any 4-day window, AND
- At least 2 completions in any 6-day window
This prevents both long gaps and insufficient frequency.
All properties use the OWH_ prefix by default (configurable via org-window-habit-property-prefix).
The OWH_CONFIG property is the recommended approach. It contains all habit parameters in a single plist and supports versioned configurations. See “Unified CONFIG Property” above for details.
For backwards compatibility, you can use individual properties instead of OWH_CONFIG:
| Property | Default | Description |
|---|---|---|
OWH_WINDOW_DURATION | (required) | Single window length (e.g., 1w, 1m, (:days 7)) |
OWH_REPETITIONS_REQUIRED | (required) | Target completions for simple window |
OWH_OKAY_REPETITIONS_REQUIRED | same as above | Minimum acceptable completions |
OWH_WINDOW_SPECS | (alternative) | List of window specs for complex requirements |
OWH_ASSESSMENT_INTERVAL | (:days 1) | How often to re-evaluate (step size for rolling window) |
OWH_RESCHEDULE_INTERVAL | (:days 1) | Minimum time after completion before rescheduling |
OWH_MAX_REPETITIONS_PER_INTERVAL | 1 | Cap on completions counted per assessment interval |
OWH_RESET_TIME | (none) | Inactive date (e.g., [2024-01-15]) to ignore completions before |
OWH_ONLY_DAYS | (none) | Restrict habit to specific days of week (e.g., M/W/F) |
Note: When OWH_CONFIG is present, scattered properties are ignored. You can migrate existing habits using M-x org-window-habit-migrate-to-config.
Like org-habit, org-window-habit displays a consistency graph in the agenda. Each character represents one assessment interval (typically one day):
- Past intervals: Show whether you were conforming (green) or not (red) at that time
- Current interval: Shows whether you need to complete today:
☐(box) - Completion needed today to stay on track✓(checkmark) - Already completed today (or not needed)
- Future intervals: Project expected conformity based on current trajectory
The colors indicate your conforming ratio:
- Green shades: On track or ahead
- Red shades: Falling behind on requirements
Key customizable variables (M-x customize-group RET org-window-habit):
| Variable | Default | Description |
|---|---|---|
org-window-habit-property-prefix | "OWH" | Prefix for org properties |
org-window-habit-preceding-intervals | 21 | Days of history shown in graph |
org-window-habit-following-days | 4 | Days of future projection in graph |
org-window-habit-conforming-color | "#4d7085" | Color for conforming intervals |
org-window-habit-not-conforming-color | "#d40d0d" | Color for non-conforming intervals |
org-window-habit-completion-needed-today-glyph | ?☐ | Character for “needed today” |
org-window-habit-completed-glyph | ?✓ | Character for “completed” |
Window durations can be specified as:
- Shorthand strings:
1d(1 day),1w(1 week),1m(1 month),2w(2 weeks) - Property lists:
(:days 7),(:weeks 1),(:months 1), or combinations like(:days 1 :hours 12)
Note that 1w shorthand converts to (:days 7), which does not align to a specific day of the week. For true week-aligned habits, use the :weeks duration type with an optional :start day:
(:weeks 1)- Aligns to Monday (default)(:weeks 1 :start :sunday)- Aligns to Sunday(:weeks 1 :start :saturday)- Aligns to Saturday (for habits aligned to the weekend)
Available start days: :sunday, :monday, :tuesday, :wednesday, :thursday, :friday, :saturday
Example: Weekly review every Monday
* TODO Weekly review
SCHEDULED: <2024-01-15 Mon .+1d>
:PROPERTIES:
:STYLE: habit
:OWH_CONFIG: (:window-specs ((:duration (:weeks 1 :start :monday) :repetitions 1)) :assessment-interval (:weeks 1 :start :monday))
:END:
Example: Sabbath observance (Friday sundown)
* TODO Shabbat preparation
SCHEDULED: <2024-01-19 Fri .+1d>
:PROPERTIES:
:STYLE: habit
:OWH_CONFIG: (:window-specs ((:duration (:weeks 1 :start :friday) :repetitions 1)) :assessment-interval (:weeks 1 :start :friday))
:END:
Some habits only make sense on specific days of the week. For example, you might go to the gym on Monday, Wednesday, and Friday, or do meal prep only on weekends. Use :only-days in OWH_CONFIG to restrict which days count toward your habit (legacy OWH_ONLY_DAYS still works).
When :only-days is set:
- Completions on non-allowed days are ignored when counting toward your goal
- Rescheduling automatically targets the next allowed day
The format is a list of day symbols: (:monday :wednesday :friday)
Available days: :sunday, :monday, :tuesday, :wednesday, :thursday, :friday, :saturday
Example: M/W/F gym habit
* TODO Go to gym
SCHEDULED: <2024-01-15 Mon .+1d>
:PROPERTIES:
:STYLE: habit
:OWH_CONFIG: (:window-specs ((:duration (:days 7) :repetitions 3)) :only-days (:monday :wednesday :friday))
:END:
This requires 3 gym visits per week, but only Monday, Wednesday, and Friday completions count. If you complete on Tuesday by mistake, it won’t count toward your goal. After completing on Monday, the habit reschedules to Wednesday (skipping Tuesday).
Example: Weekend meal prep
* TODO Meal prep for the week
SCHEDULED: <2024-01-20 Sat .+1d>
:PROPERTIES:
:STYLE: habit
:OWH_CONFIG: (:window-specs ((:duration (:days 7) :repetitions 1)) :only-days (:saturday :sunday))
:END:
This requires meal prep once per week, but only on weekends. Completing on a weekday won’t count.