Skip to content

Workflow: Capture a Task

Realizes: spec_v3.md §1.1 Active Task Capture, §5.5.1 Natural Language Task Parsing.

Scenario

Nick sends a Discord DM to Donna:

"Remind me to review the quarterly plan tomorrow at 10am, high priority."

Donna parses the message, classifies priority, deduplicates against existing tasks, persists the row, schedules reminders, and replies.

Path Through the Code

  1. Inbound. donna.integrations.discord_bot receives on_message and forwards (text, user_id, channel_id) to the orchestrator.
  2. Orchestrator intent routing. donna.orchestrator identifies this as a task-capture intent and invokes the parse_task skill.
  3. Skill execution. donna.skills.executor.SkillExecutor runs the YAML-defined parse_task skill step-by-step.
  4. Model call. donna.models.router.ModelRouter.complete routes to the configured model for task_parse (see config/donna_models.yaml) and logs an invocation row via donna.logging.invocation_logger.
  5. Schema validation. The structured output is validated against schemas/task_parse_output.json. The parser emits a structured time_intent (the when of the task); if the model omits it, an LLM-free fallback re-extracts common date phrasings. See Task System → Time Intent.
  6. Dedup. donna.tasks.dedup runs deduplication (spec_v3.md §5.3 — fuzzy title match + LLM semantic comparison).
  7. Persist. donna.tasks.database writes the row (including time_intent_json, from which deadline / deadline_type are derived); donna.integrations.supabase_sync mirrors it.
  8. Route. The routing gate inspects the time_intent. Because this task is time-bound (exact, "tomorrow at 10am"), it goes to the Scheduler immediately — it is not deferred for the Challenger. An undated task would instead stay in backlog; a recurring one goes to the automation pipeline.
  9. Schedule. donna.scheduling places the task and enqueues reminder cadence (T-24h, T-1h, T). If no slot exists before the deadline, the task transitions to needs_scheduling (per config/task_states.yaml) instead of stranding in backlog.
  10. Reply. The Discord bot confirms back with slot-aware, persona-voice copy generated by donna.integrations.confirmation_copy — e.g. the confirmed time for a scheduled task, a "couldn't find a slot" message when unplaceable, or a backlog note for undated tasks. (This replaces the old static "Scheduled: pending." reply.)

Sequence

sequenceDiagram
    participant U as User
    participant D as discord_bot
    participant O as orchestrator
    participant S as SkillExecutor
    participant R as ModelRouter
    participant V as schema validator
    participant DB as tasks.database
    participant SC as scheduling

    U->>D: DM text
    D->>O: route(text, user_id)
    O->>S: run(parse_task, text)
    S->>R: complete(prompt, "task_parse", user_id)
    R-->>S: structured JSON
    S->>V: validate(task_parse_output)
    V-->>S: ok
    S->>S: run(dedup_check, parsed)
    S-->>O: Task (with time_intent)
    O->>DB: INSERT tasks WHERE user_id=?
    O->>SC: routing_gate.route(time_intent, priority)
    SC->>SC: time-bound → schedule now (skip Challenger)
    SC->>SC: enqueue reminders
    O-->>D: persona-voice confirmation (slot-aware)
    D-->>U: reply

Observability

Every hop emits a structured log line with correlation_id, user_id, task_id. See Domain → Observability.