Skip to content

calternal_notes_core::tasks::build

build_task_file + append_inbox_line — canonical Task Note writers.

  • build_task_file: produce a byte-canonical new Task Note from a BuildTaskFileInput. The output is immediately readable by extract_task_index (T6) without any round-trip loss: every value that would be mis-parsed by YAML is double-quoted via the shared needs_quote rule from frontmatter.rs.

  • append_inbox_line: byte-stable append of - [ ] <title>\n to a legacy Checkbox file. Existing bytes are never rewritten.

Frontmatter field order (#27 T6, spec A §C.2 canonical — amends tasks spec §4.1)

Section titled “Frontmatter field order (#27 T6, spec A §C.2 canonical — amends tasks spec §4.1)”

calternal-id, title, priority, scheduled, due, repeat, estimate, area, created

status: todo is always present. It marks the file as a Task independently of its Home folder and is also its canonical initial status.

title and created are always present; every other field (INCLUDING the new calternal-id/estimate) is emitted only when Some — see BuildTaskFileInput’s doc comment for why calternal-id is optional despite the spec calling it “required for file builds”. Date fields use CivilDate::to_ymd (→ YYYY-MM-DD, date-only — the datetime-with-time format T7/T8 add is a LATER task, out of this one’s scope); priority uses TaskPriority::as_word (→ “low”|“medium”|“high”|“urgent”). Neither is ever quoted — they never contain YAML-special characters.

Quoting split: frontmatter vs. body vs. free-form prose

Section titled “Quoting split: frontmatter vs. body vs. free-form prose”

String scalars in YAML frontmatter (calternal-id, title, repeat, estimate, area) go through push_scalar, which calls frontmatter::needs_quote and, when true, wraps the value in "..." with \ and " escaped — exactly mirroring emit_scalar in frontmatter.rs so the same quoting rule is never duplicated.

The - [ ] <title> BODY line and the free-form body PROSE block (#27 T6) are NOT YAML. Both are written verbatim, even when they contain a colon or other YAML-special character — quoting them would corrupt the display text (title) or mangle the user’s own prose (body).

Source: crates/calternal-notes-core/src/tasks/build.rs

pub fn append_inbox_line(text: &str, title: &str) -> String

Append - [ ] <title>\n to a legacy Checkbox list such as tasks/inbox.md; new task capture writes a Task Note instead (#430).

Byte-stable: existing bytes are NEVER modified. The return value is always text + (optional "\n") + "- [ ] <title>\n".

Newline boundary rule: if text is non-empty and does NOT already end with \n, one is inserted before the new line so the file stays well-formed. This avoids corrupting the previous line by jamming the checkbox onto it.

Source: crates/calternal-notes-core/src/tasks/build.rs:208

pub fn build_task_file(input: &BuildTaskFileInput) -> String

Build a canonical new Task Note from input.

Output format:

---
[calternal-id: <uuid>]
title: <title>
[priority: <word>]
[scheduled: YYYY-MM-DD]
[due: YYYY-MM-DD]
[repeat: <string>]
[estimate: <string>]
[area: <string>]
status: todo
created: YYYY-MM-DD
---
[<body prose, verbatim>
]
- [ ] <title verbatim>

start is an Obsidian import field. The writer copies it to scheduled only when scheduled is absent, and never emits a start: key (#430). Fields in square brackets appear only when Some/non-empty. title and created are always present. The canonical field order is fixed (#27 T6, spec A §C.2, amending tasks spec §4.1) so extract_task_index always finds fields in a predictable position.

body (T6): when Some and non-empty, emitted VERBATIM between the closing fence and the root checkbox, followed by a blank separator — the exact # <title>\n\n<body>\n shape build_standalone_note (T5) uses for notes, applied here between frontmatter and checkboxes instead of after an H1. None/empty adds zero bytes: the output is IDENTICAL to the pre-T6 (no body) layout — frontmatter → one blank line → checkbox.

Round-trip guarantee: the Task projector reads the Note built from input recovers every input field — title, priority, dates, recurrence, area, created, PLUS (T6) calternal-id and body — from the resulting TaskIndexEntry File row. estimate is written and preserved by every subsequent byte-stable rewrite (set_task_frontmatter_field), but is not yet a projected TaskIndexEntry field (no v1 consumer reads it back through the projector — see BuildTaskFileInput::estimate’s doc comment).

Source: crates/calternal-notes-core/src/tasks/build.rs:93