You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
README rewritten for the markdown task-list format:
- Folder layout uses .md filenames
- Editing rules show standard markdown task list with the [/]
and [!] custom states called out as non-standard
- "Migrating from pre-0.2.0" section explains
migrate_to_markdown() with preview-then-commit flow
- Examples updated throughout (.txt -> .md, [X] - text -> - [X] text)
- recurring.txt section reframes the workflow ("recurring lives
in the manifest, not as inline `*` markers")
- Coverage of preview mode adds migrate_to_markdown to the list
- .gitignore tip drops `*.md` since .md is now canonical
- Troubleshooting adds a mixed-extension hint
CLAUDE.md updates:
- Modules list adds R/recurring.R and R/migrate.R, calls out
the dual-format .parse_task_line() helper in R/parse.R
- Preview mode list adds migrate_to_markdown
- Task File Format section rewritten as markdown, notes the
parser still reads pre-0.2.0 files
2.`inherit_recur_to_parents()` - Bubble `recur=TRUE` up to parent tasks
24
24
3.`rollup_status()` - Update parent status based on children (all x → x, any / → /, etc.)
25
-
4.`write_todo_txt()` - Write data.frame back to .txt format
25
+
4.`write_todo_txt()` - Write data.frame back to .md format
26
26
27
27
**Key modules:**
28
-
-`R/parse.R` - Text parsing to data.frame (internal/full schema)
28
+
-`R/parse.R` - Text parsing to data.frame (internal/full schema). `.parse_task_line()` is the dual-format lexer used by `parse_todo`, `roll_day`, `next_day`, and `tasks()`.
29
29
-`R/tasks.R` - Agent-facing read API (`tasks()`)
30
30
-`R/rollup.R` - Parent status calculation
31
31
-`R/advance.R` - Period advancement logic (weekly/monthly/quarterly rollover)
-`R/io.R` - File I/O (markdown writer, html mirror)
35
37
-`R/config.R` - Configuration via `config.yaml` or `hacer_config.R`
36
38
37
39
## Agent-facing read API
@@ -53,23 +55,29 @@ r -e 'tinypkgr::check()'
53
55
54
56
## Preview mode
55
57
56
-
Every mutator (`roll_day`, `run_monday`, `fix_parents`, `next_day`, `sync_from_daily`, `instantiate_todo`) accepts `preview = TRUE` and returns a `hacer_preview` describing the would-be change without writing. Set `HACER_PREVIEW=1` to flip the default — useful for one-shot agent invocations that should be inspectable before they touch the user's todo repo. Internals live in `R/preview.R`; each mutator builds a `targets` list of `path -> new_lines` and dispatches via `.write_or_preview()`.
58
+
Every mutator (`roll_day`, `run_monday`, `fix_parents`, `next_day`, `sync_from_daily`, `instantiate_todo`, `migrate_to_markdown`) accepts `preview = TRUE` and returns a `hacer_preview` describing the would-be change without writing. Set `HACER_PREVIEW=1` to flip the default — useful for one-shot agent invocations that should be inspectable before they touch the user's todo repo. Internals live in `R/preview.R`; each mutator builds a `targets` list of `path -> new_lines` and dispatches via `.write_or_preview()`.
57
59
58
-
## Task File Format
60
+
## Task File Format (0.2.0+)
59
61
60
-
```
61
-
# Section Header
62
+
```markdown
63
+
# todo_yymmdd_daily.md
64
+
65
+
## Monday
62
66
63
-
[ ] - Parent Task
64
-
[/] - Child in progress
65
-
[x] - Child done
66
-
[ ] -*Recurring Task
67
+
-[ ] Parent Task
68
+
-[/] Child in progress
69
+
-[x] Child done
70
+
-[!] Blocked thing
67
71
```
68
72
69
-
- Two spaces per indent level
70
-
- Status: `[ ]` todo, `[/]` in progress, `[x]` done, `[!]` blocked
71
-
-`*` prefix = recurring (preserved across rollovers)
72
-
-`[!]` is sticky: rollup gives it precedence over all other statuses, and `roll_day()` / `run_monday()` / `next_day()` preserve it verbatim until a human or agent changes it
73
+
- Standard markdown task list. Two spaces per indent level.
74
+
- Status: `[ ]` todo, `[/]` in progress, `[x]` done, `[!]` blocked. `[/]` and `[!]` are non-standard but render fine in Obsidian.
75
+
- Day sections in Daily are `## ` (H2). The first line is the H1 file-name header.
76
+
- Recurring tasks are declared in `recurring.txt`, not as inline `*` markers.
77
+
78
+
The dual-format parser still reads pre-0.2.0 files (`[X] - text` syntax in `.txt` files with `# Section` H1 day headers). The writer never emits the legacy format. `migrate_to_markdown()` does a one-shot conversion of the live dir.
79
+
80
+
-`[!]` is sticky: rollup gives it precedence over all other statuses, and `roll_day()` / `run_monday()` / `next_day()` preserve it verbatim until a human or agent changes it.
> Pre-0.1.7 repos used capitalized `ToDo_YYMMDD_*.txt`filenames. Readers stay case-insensitive so legacy files keep working — new writes always emit the lowercase form.
43
+
> Pre-0.2.0 repos used `[X] - text` syntax in `.txt`files. Readers still understand both formats during transition; new writes always emit standard markdown task lists in `.md`. Run `migrate_to_markdown()` to convert your live files in one shot.
44
44
45
45
## Editing rules (syntax)
46
46
47
-
- Two spaces per indent level for sub-tasks.
48
-
- Status: `[ ]` = todo, `[/]` = in progress, `[x]` = done, `[!]` = blocked (attention needed).
49
-
- Recurring: prefix name with `*` (e.g., `[ ] -*Exercise`) → `recur = TRUE`.
47
+
Standard markdown task list. Two spaces per indent level:
48
+
49
+
```markdown
50
+
# todo_260427_daily.md
51
+
52
+
## Monday
53
+
54
+
-[ ] House
55
+
-[/] Drywall
56
+
-[x] Trim
57
+
-[!] Permit blocked on city review
58
+
59
+
## Tuesday
60
+
61
+
-[ ] CO2
62
+
```
63
+
64
+
- Status: `[ ]` = todo, `[/]` = in progress, `[x]` = done, `[!]` = blocked (attention needed). `[x]` and `[ ]` are vanilla markdown; `[/]` and `[!]` are custom states (Obsidian renders them, GitHub falls back to plain text).
65
+
- Day sections in Daily are H2 headers (`## Monday`).
66
+
- Recurring tasks live in `recurring.txt`, not as inline `*` markers in the file. The pre-0.2.0 `*` marker is still parsed (so legacy files keep working) but the writer never emits it.
# day-to-day: copy yesterday forward, drop done non-recurring, log to done.log
107
124
hacer::roll_day()
108
125
109
126
# read everything as a data.frame (parsed from this_week/)
110
127
hacer::tasks()
128
+
129
+
# convert legacy .txt files to .md (one-shot)
130
+
hacer::migrate_to_markdown()
111
131
```
112
132
113
133
> Tip: add `use_repo("~/todo")` to `~/.Rprofile` so you don't need to call it each session.
114
134
135
+
## Migrating from pre-0.2.0
136
+
137
+
Older repos used `[X] - text` syntax in `.txt` files. The dual-format parser keeps reading them, but the writer no longer emits that style. To convert in one shot:
138
+
139
+
```r
140
+
library(hacer)
141
+
use_repo("~/todo")
142
+
143
+
# Inspect first — preview reports the would-be conversions
144
+
hacer::migrate_to_markdown(preview=TRUE)
145
+
146
+
# Then commit
147
+
hacer::migrate_to_markdown()
148
+
```
149
+
150
+
`migrate_to_markdown()` walks `this_week/` only (archive files stay legacy unless you decide they need attention), rewrites each `.txt` as `.md` in the markdown task-list syntax, and removes the `.txt` source. It also surfaces a list of any tasks that carried the legacy `*` recurring marker — copy those paths into `recurring.txt` so they keep recurring, otherwise they become one-offs.
151
+
115
152
## For LLM CLI agents
116
153
117
154
hacer's functions work fine as one-shot R calls from any agent that can spawn `Rscript` or `r` (Claude Code, Codex, etc.). Point hacer at a repo with the `HACER_REPO` environment variable — no `use_repo()` required:
118
155
119
156
```bash
120
157
HACER_REPO=~/todo r -e 'hacer::run_monday()'
121
158
HACER_REPO=~/todo r -e 'hacer::next_day()'
122
-
HACER_REPO=~/todo r -e 'hacer::fix_parents("~/todo/this_week/todo_250915_daily.txt")'
159
+
HACER_REPO=~/todo r -e 'hacer::fix_parents("~/todo/this_week/todo_260427_daily.md")'
123
160
```
124
161
125
162
Resolution order for the repo path is: `repo_dir` argument → `options("hacer.repo")` → `HACER_REPO` env var → `tools::R_user_dir("hacer", "data")`. The env var makes the "stateless one-shot" case ergonomic. The `R_user_dir()` fallback is CRAN-safe but ugly (`~/.local/share/R/hacer/` on Linux), so most users `instantiate_todo("~/todo")` and persist `use_repo("~/todo")` in `~/.Rprofile`.
Set `HACER_PREVIEW=1` to flip the default for a one-shot CLI agent so it never accidentally writes:
@@ -148,7 +185,7 @@ HACER_REPO=~/todo HACER_PREVIEW=1 r -e 'hacer::run_monday()'
148
185
HACER_REPO=~/todo HACER_PREVIEW=1 r -e 'hacer::roll_day()'
149
186
```
150
187
151
-
Covers `roll_day()`, `run_monday()`, `fix_parents()`, `next_day()`, `sync_from_daily()`, and `instantiate_todo()`. The preview lists `files_created`, `files_modified`, line-level diffs, and any `done.log` lines that would be appended.
188
+
Covers `roll_day()`, `run_monday()`, `fix_parents()`, `next_day()`, `sync_from_daily()`, `instantiate_todo()`, and `migrate_to_markdown()`. The preview lists `files_created`, `files_modified`, line-level diffs, and any `done.log` lines that would be appended.
0 commit comments