10. Dependencies and Reminders
10.1 Purpose
This section defines canonical semantics for task dependencies (blocked_by) and task reminders (reminders).
10.2 Dependencies (blocked_by)
10.2.1 Data shape
blocked_by MUST be a list of dependency entries.
Each entry MUST be an object with:
uid(required): reference to a blocking task (link or string)reltype(required): one ofFINISHTOSTARTSTARTTOSTARTFINISHTOFINISHSTARTTOFINISH
gap(optional): ISO 8601 duration string
If reltype is omitted on read in compatibility mode, implementations MAY treat it as FINISHTOSTART and SHOULD emit a warning.
10.2.2 UID normalization
Implementations SHOULD normalize uid values to a canonical reference representation on write.
If link formats are supported, both wikilink and markdown-link forms MAY be read. Canonical write form MUST be documented. Link parsing and resolution MUST follow §11.
10.2.3 Dependency uniqueness
Within a task, dependency entries are keyed by normalized uid.
Policy is configuration-driven and MUST be deterministic:
- when
dependencies.enforce_unique_uid=true(default), duplicate normalizeduidvalues MUST NOT be accepted as canonical persisted state:- strict mode: duplicates MUST fail validation/write with
duplicate_dependency_uid; - permissive mode: implementations MAY either fail or normalize to one entry, but MUST emit
duplicate_dependency_uid.
- strict mode: duplicates MUST fail validation/write with
- when
dependencies.enforce_unique_uid=false, duplicates MAY be preserved as compatibility behavior.
The active policy MUST be documented in conformance claims.
10.2.4 Self-dependency
A task MUST NOT depend on itself.
Self-dependency is a validation error.
10.2.5 Blocking semantics (v0.1)
For v0.1, blocking evaluation MUST be status-presence based:
- A task is blocked if it has at least one unresolved dependency.
- A dependency on a resolvable task is unresolved when the referenced task is not in a completed status.
- Completed status MUST be determined from configured
status.completed_values. - For recurring referenced tasks in v0.1, unresolved/resolved evaluation MUST use base
statusonly;complete_instances/skipped_instancesare not consulted. - When a referenced task is missing/unresolvable, whether that missing target contributes to blocked-state evaluation MUST follow
dependencies.treat_missing_target_as_blocked(§9.11, defaulttrue).
For v0.1, reltype and gap are preserved and validated but MUST NOT change the unresolved/resolved decision.
10.2.6 Missing referenced task
When uid cannot be resolved:
- implementations SHOULD emit
unresolved_dependency_target. - blocked-state contribution for this missing target MUST follow
dependencies.treat_missing_target_as_blocked(§9.11). - issue severity SHOULD follow
dependencies.unresolved_target_severity(default:warning). - for
blocked_by.uid, this dependency-specific severity policy MUST take precedence overlinks.unresolved_default_severity. - parse failures that produce
invalid_link_formatand containment violations that producepath_traversalremain error-severity conditions from §11. - if
dependencies.require_resolved_uid_on_write=true, add/update MUST fail with error.
10.2.7 Cycles
Implementations MUST reject direct self-cycles.
Detection of multi-hop dependency cycles is RECOMMENDED but not required for core-lite or recurrence profiles.
10.2.8 Reverse relation field
Some implementations maintain reverse relationships (for example blocking). Such fields are derived and non-canonical in this spec unless explicitly mapped.
If maintained, reverse updates SHOULD remain consistent with blocked_by edits.
10.2.9 Dependency operation semantics
Add dependency
Add dependency MUST:
- validate entry shape,
- handle duplicates by policy (preserve, normalize, or reject),
- preserve unrelated dependency entries,
- update
date_modifiedon change.
Remove dependency
Remove dependency MUST remove by normalized uid and be idempotent.
Replace dependencies
Replace behavior MUST be explicit operation mode (not default for patch update).
10.2.10 Dependency examples
Example entry:
blockedBy:
- uid: "[[prepare-metrics]]"
reltype: FINISHTOSTART
gap: PT4H
Example unresolved dependency (target missing):
blockedBy:
- uid: "[[non-existent-task]]"
reltype: FINISHTOSTART
10.3 Reminders (reminders)
10.3.1 Data shape
reminders MUST be a list of reminder entries.
Each reminder MUST include:
id(required): unique string within the tasktype(required):absoluteorrelative
Optional field:
descriptionstring
Type-specific fields:
absolute: requiresabsoluteTimedatetimerelative: requiresrelatedTo(dueorscheduled) andoffset(ISO 8601 duration)
10.3.2 Reminder uniqueness
Reminder id values MUST be unique within the task.
If duplicates occur:
- strict mode: MUST raise
duplicate_reminder_id. - permissive mode: MAY normalize deterministically and emit warning.
10.3.3 Relative reminder base
relatedTo MUST reference semantic role due or scheduled.
If the referenced role is absent, the reminder is unresolved.
10.3.4 Trigger instant computation
Trigger instant MUST be computed as follows:
- If
type=absolute, trigger =absoluteTimeinstant. - If
type=relative,- resolve base field from
relatedTo, - if base is datetime: use that instant,
- if base is date: convert to local datetime at configured
reminders.date_only_anchor_time, - trigger = base +
offset.
- resolve base field from
If reminders.date_only_anchor_time is not configured, implementations MUST use 00:00 local time.
10.3.5 Offset semantics
offset MUST be a valid ISO 8601 duration with optional sign.
- negative offset = before base
- positive offset = after base
- zero offset = at base instant
10.3.6 Invalid mixed fields
Entries with incompatible field combinations MUST fail validation in strict mode.
Examples:
type=absolutewithrelatedToand noabsoluteTimetype=relativewithabsoluteTimeand missingoffset
10.3.7 Reminder ordering
When computing reminder schedules, implementations MUST sort by trigger instant ascending.
For identical trigger instants, implementations MUST use stable tie-break ordering by id ascending.
10.3.8 Reminder operation semantics
Add reminder
Add reminder MUST validate shape and unique id, then update date_modified.
If id is omitted by caller and implementation supports auto-ID generation, generated IDs MUST be unique within the task.
Update reminder
Update reminder MUST address reminders by id and be patch-by-default.
Remove reminder
Remove reminder by id MUST be idempotent.
10.3.9 Default reminders
If defaults.reminders is configured (see §9):
- create without explicit reminders MUST apply defaults.
- create with explicit reminders MUST follow
reminders.apply_defaults_when_explicit(§9.15):false(default): explicit reminders replace defaults.true: explicit reminders are merged with defaults.
Deterministic merge rules when apply_defaults_when_explicit=true:
- Start with explicit reminders in caller order.
- Append each default reminder whose
idis not already present. - If explicit and default reminders share an
id, explicit reminder MUST win.
10.3.10 Reminder examples
Relative reminder:
reminders:
- id: due_minus_15m
type: relative
relatedTo: due
offset: -PT15M
Absolute reminder:
reminders:
- id: call_now
type: absolute
absoluteTime: 2026-02-20T09:00:00Z
10.3.11 Reminder resolution error handling
If relative reminder base is unavailable (relatedTo=due but no due field):
- strict mode: validation error
unresolvable_reminder_base. - permissive mode: warning and reminder excluded from trigger computation.
10.4 Interactions
10.4.1 Rename interaction
If implementation supports rename/reference updates, dependency uid references SHOULD be updated consistently with other link references.
10.4.2 Completion interaction
Changing task completion state does not automatically remove dependencies or reminders unless explicitly configured.
10.4.3 Archive interaction
Archive operations MAY suppress reminder delivery in runtime systems, but archive MUST NOT silently delete reminder records from persisted frontmatter unless explicitly requested.