Skip to content

donna.scheduling.time_intent

donna.scheduling.time_intent

TimeIntent — the structured representation of when a task should happen.

Captures the five temporal kinds Donna recognizes (exact, window, constrained, recurring, none) and derives the legacy deadline / deadline_type values so existing consumers (reminders, overdue detector, weekly planner) keep working unchanged. See docs/superpowers/specs/2026-06-05-challenger-and-scheduling-intake-design.md.

Kind module-attribute

Kind = Literal['exact', 'window', 'constrained', 'recurring', 'none']

Strictness module-attribute

Strictness = Literal['hard', 'soft']

TimeIntent dataclass

TimeIntent(kind: Kind = 'none', due_at: datetime | None = None, earliest: datetime | None = None, latest: datetime | None = None, strictness: Strictness = 'soft', constraints: dict[str, Any] | None = None, recurrence: dict[str, Any] | None = None)

Normalized temporal intent extracted from a task.

Parameters:

Name Type Description Default
kind Kind

One of exact | window | constrained | recurring | none.

'none'
due_at datetime | None

Concrete deadline for exact.

None
earliest datetime | None

Lower bound for window / constrained.

None
latest datetime | None

Upper bound for window / constrained.

None
strictness Strictness

hard | soft. Ignored when kind == none/recurring.

'soft'
constraints dict[str, Any] | None

e.g. {"weekday": [0], "time_of_day": "morning"} for constrained.

None
recurrence dict[str, Any] | None

e.g. {"rrule_or_cron": "0 9 * * 3", "human_readable": "every Wednesday 9am"}.

None

kind class-attribute instance-attribute

kind: Kind = 'none'

due_at class-attribute instance-attribute

due_at: datetime | None = None

earliest class-attribute instance-attribute

earliest: datetime | None = None

latest class-attribute instance-attribute

latest: datetime | None = None

strictness class-attribute instance-attribute

strictness: Strictness = 'soft'

constraints class-attribute instance-attribute

constraints: dict[str, Any] | None = None

recurrence class-attribute instance-attribute

recurrence: dict[str, Any] | None = None

from_dict classmethod

from_dict(data: dict[str, Any]) -> TimeIntent

Build a TimeIntent from a loosely-typed dict (e.g. LLM JSON).

Source code in src/donna/scheduling/time_intent.py
@classmethod
def from_dict(cls, data: dict[str, Any]) -> TimeIntent:
    """Build a TimeIntent from a loosely-typed dict (e.g. LLM JSON)."""
    return cls(
        kind=data.get("kind", "none"),
        due_at=_parse_dt(data.get("due_at")),
        earliest=_parse_dt(data.get("earliest")),
        latest=_parse_dt(data.get("latest")),
        strictness=data.get("strictness", "soft"),
        constraints=data.get("constraints"),
        recurrence=data.get("recurrence"),
    )

from_json classmethod

from_json(raw: str | None) -> TimeIntent

Deserialize from the JSON string stored on the task row.

Source code in src/donna/scheduling/time_intent.py
@classmethod
def from_json(cls, raw: str | None) -> TimeIntent:
    """Deserialize from the JSON string stored on the task row."""
    if not raw:
        return cls(kind="none")
    return cls.from_dict(json.loads(raw))

to_json

to_json() -> str

Serialize to a JSON string for the time_intent_json column.

Source code in src/donna/scheduling/time_intent.py
def to_json(self) -> str:
    """Serialize to a JSON string for the ``time_intent_json`` column."""
    out: dict[str, Any] = {"kind": self.kind, "strictness": self.strictness}
    for name in ("due_at", "earliest", "latest"):
        value = getattr(self, name)
        if value is not None:
            out[name] = value.isoformat()
    if self.constraints is not None:
        out["constraints"] = self.constraints
    if self.recurrence is not None:
        out["recurrence"] = self.recurrence
    return json.dumps(out)

derive_deadline

derive_deadline(ti: TimeIntent) -> datetime | None

Back-compat deadline: due_at (exact) or latest (window/constrained); else None.

Source code in src/donna/scheduling/time_intent.py
def derive_deadline(ti: TimeIntent) -> datetime | None:
    """Back-compat deadline: due_at (exact) or latest (window/constrained); else None."""
    if ti.kind == "exact":
        return ti.due_at
    if ti.kind in ("window", "constrained"):
        return ti.latest
    return None

derive_deadline_type

derive_deadline_type(ti: TimeIntent) -> str

Back-compat deadline_type: strictness for time-bound kinds, else 'none'.

Source code in src/donna/scheduling/time_intent.py
def derive_deadline_type(ti: TimeIntent) -> str:
    """Back-compat deadline_type: strictness for time-bound kinds, else 'none'."""
    if ti.kind in ("exact", "window", "constrained"):
        return ti.strictness
    return "none"