I appreciate everyone’s help getting this working.
I spent way too much time on this, so in the hopes that this is helpful to someone in case anyone else wants to recreate something similar, here’s the entirety of what I came up with:
I store lists of tasks in tiddlers with a consistent naming convention, then create a new journal tiddler, and append all of the relevant tiddlers for that date. It allows arbitrary frequencies for tasks that happen every n (currently n goes from 1 to 11, but that can be increased if needed by changing the number in <$list filter=[range[1],[11]] variable=n>
) days, weeks (on specified weekday), months (on specified day number or days from end of month), or years (on specified date). It also lets me offset them; so if I have two tasks repeating every second day, I can specify them on the same day or alternating days (this is the parameter m in the code below). Each tiddler stores a list of tasks, one per line. Additional blank lines can be used for clarity, as they will be discarded later. At some point, if they become clutter, I may move them to $:/dev/tasks/… and update the code below appropriately.
Task list naming scheme (n is for frequency, m runs from 0 to n-1):
Every n days on day m: every_n_days_m
- So “every_1_days_0” is for tasks that occur every single day
- “every_3_days_0” “every_3_days_1” and “every_3_days_2” are for tasks that occur every third day, with 0, 1, and 2 changing which day of the three-day cycle they appear on (day counting based on unix standard time)
Every n weeks (on week m) on a specified weekday: every_n_weeks_DDD_m
- Similarly, “every_2_weeks_Wednesday_0” and “every_2_weeks_Wednesday_1” are for tasks that occur every second Wednesday, and the 0 or 1 determines which of the alternating weeks they occur on (week counting also based on unix standard time).
- “every_n_months_22_m”
Every n months (on month m) on a specified date: every_n_months_DD_m
or
Every n months (on month m), a number of days from the end of the month: every_n_months_-DD_m
- So “every_2_months_13_0” happens every second month on the 13th.
- “every_1_months_-7_0” happens 7 days before the last of the month, every month
- Monthly counting is based on year*12+month#
Every n years (on year m): every_n_years_MMM_DD_m
- So “every_1_year_October_1_0” happens every October 1st.
The main workhorse is “$:/dev/newJournalAction” tagged with “$:/tags/StartupAction/PostRender” so it automatically runs at startup. If the journal already exists, it skips the creation part and just opens the journal. If the journal doesn’t exist, it is created with the initial text “@@.todo”, then generates all of the tiddler names relevant for the current date, and appends them (non-existent tiddlers don’t affect the text, and it even removes extra blank lines and then adds "[ ] " before each entry), then finally adds the trailing “@@” required for Kara. It uses the default new journal title and tags (from settings). There are probably many ways to make this more concise or efficient, but it works and I’ve already spent too much time on this so I probably won’t look at it again for a long time (sometime after I’ve forgotten everything that I learned through this process, so I end up having to relearn it all again).
Then I’ve got a button “$:/dev/NewJournalButton” tagged with “$:/tags/PageControls” so I can show it instead of the original new journal button on the sidebar. This basically just copies the existing new journal button, but calls my action instead.
Finally I’ve got a viewtemplate “$:/dev/templates/JournalView”, which applies to all tiddlers tagged with “Journal”.
“$:/dev/newJournalAction”:
<!--------
key:
n - frequency, every nth day/week/etc. (can be 1 for daily/weekly/etc.)
m - which nth day, runs from 0 to n-1
Daily: every_n_days_m
Weekly: every_n_weeks_DDD_m
Monthly: every_n_months_DD_m (DD -> negative for days from end of month)
Yearly: every_n_years_MMM_DD_m
-------->
\define journalChores()
{{templates/dailyChores}}
\end
\define get-tags() $(textFieldTags)$ $(tagsFieldTags)$
<$let lf="
"
taskPre="[ ] "
journalTitleTemplate={{$:/config/NewJournal/Title}} textFieldTags={{$:/config/NewJournal/Tags}} tagsFieldTags={{$:/config/NewJournal/Tags!!tags}}>
<$wikify name="journalTitle" text="<$macrocall $name='now' format=<<journalTitleTemplate>>/>">
<$reveal type="match" state=<<journalTitle>> text="">
<$action-createtiddler $basetitle=<<journalTitle>> tags=<<get-tags>> text=@@.todo >
<$let
dayOfWeek=<<now DDD>>
dayOfMonth=<<now DD>>
month=<<now MMM>>
n_month=<<now MM>>
year=<<now YYYY>>
lastDayOfMonth={{{ [<year>remainder[4]match[0]then<n_month>match[2]then[29]]
~[[31 28 31 30 31 30 31 31 30 31 30 31]split[ ]nth<n_month>] }}}
dayFromEndOfMonth={{{ [<lastDayOfMonth>subtract<dayOfMonth>] }}}
intDay={{{ [<now YYYY0MM0DD000000000Z>format:date[TIMESTAMP]divide[86400000]] }}}
intWeek={{{ [<now YYYY0MM0DD000000000Z>format:date[TIMESTAMP]divide[86400000]add[4]divide[7]floor[]] }}}
intMonth={{{ [<now YYYY>multiply[12]add<now MM>] }}}
>
<$list filter=[range[1],[11]] variable=n>
<$let m={{{ [<intDay>remainder<n>] }}}
tiddlerToAppend={{{ every_ [<n>] _days_ [<m>] +[join[]] }}}
>
<$action-setfield $tiddler=<<createTiddler-title>>
text={{{ [<createTiddler-title>get[text]] [<tiddlerToAppend>get[text]split<lf>!is[blank]addprefix<taskPre>] +[join<lf>] }}} />
</$let>
<$let m={{{ [<intWeek>remainder<n>] }}}
tiddlerToAppend={{{ every_ [<n>] _weeks_ [<dayOfWeek>] _ [<m>] +[join[]] }}}
>
<$action-setfield $tiddler=<<createTiddler-title>>
text={{{ [<createTiddler-title>get[text]] [<tiddlerToAppend>get[text]split<lf>!is[blank]addprefix<taskPre>] +[join<lf>] }}} />
</$let>
<$let m={{{ [<intMonth>remainder<n>] }}}
tiddlerToAppend={{{ every_ =[<n>] _months_ =[<dayOfMonth>] _ =[<m>] +[join[]] }}}
>
<$action-setfield $tiddler=<<createTiddler-title>>
text={{{ [<createTiddler-title>get[text]] [<tiddlerToAppend>get[text]split<lf>!is[blank]addprefix<taskPre>] +[join<lf>] }}} />
</$let>
<$let m={{{ [<intMonth>remainder<n>] }}}
tiddlerToAppend={{{ every_ =[<n>] _months_- =[<dayFromEndOfMonth>] _ =[<m>] +[join[]] }}}
>
<$action-setfield $tiddler=<<createTiddler-title>>
text={{{ [<createTiddler-title>get[text]] [<tiddlerToAppend>get[text]split<lf>!is[blank]addprefix<taskPre>] +[join<lf>] }}} />
</$let>
<$let m={{{ [<year>remainder<n>] }}}
tiddlerToAppend={{{ every_ =[<n>] _years_ =[<month>] =_ =[<dayOfMonth>] =_ =[<m>] +[join[]] }}}
>
<$action-setfield $tiddler=<<createTiddler-title>>
text={{{ [<createTiddler-title>get[text]] [<tiddlerToAppend>get[text]split<lf>!is[blank]addprefix<taskPre>] +[join<lf>] }}} />
</$let>
</$list>
</$let>
<$action-setfield $tiddler=<<createTiddler-title>>
text={{{ [<createTiddler-title>get[text]] @@ +[join<lf>] }}} />
</$action-createtiddler>
</$reveal>
<$action-navigate $to=<<journalTitle>> />
</$wikify>
</$let>
“$:/dev/NewJournalButton”:
\define journalChores()
{{templates/dailyChores}}
\end
\define get-tags() $(textFieldTags)$ $(tagsFieldTags)$
\define journalAction()
{{$:/dev/newJournalAction}}
\end
\whitespace trim
\define journalButton()
\whitespace trim
<$button tooltip={{$:/language/Buttons/NewJournal/Hint}} aria-label={{$:/language/Buttons/NewJournal/Caption}} class=<<tv-config-toolbar-class>> actions=<<journalAction>> >
<$list filter="[<tv-config-toolbar-icons>match[yes]]">
{{$:/core/images/new-journal-button}}
</$list>
<$list filter="[<tv-config-toolbar-text>match[yes]]">
<span class="tc-btn-text">
<$text text={{$:/language/Buttons/NewJournal/Caption}}/>
</span>
</$list>
</$button>
\end
<<journalButton>>
“$:/dev/templates/JournalView”:
<$list filter="[all[current]tag[Journal]]">
<<checklist>>
<<interstitial>>
</$list>
Edit: A caveat/caution/bug that I’m aware of but don’t care enough to fix: If you specify monthly tasks on the 29, 30, or 31, they will simply not occur on months that have fewer days (and similarly for days from the end of the month).
It wouldn’t surprise me if there’s some content you could add to the task lists that breaks things (though maybe not, as they’re treated as text?), but all I care about for now is simple links, which appear to work perfectly.
Edit 2: If you want any other standard content outside of the todo list on the daily journal, you could create a separate template with whatever content, and add on creation using template instead of text, and then append the @@.todo the same as we do everything else. Or if you just want it to show up without being in the content of each journal, you can add it to the JournalView.