{
  "slug": "tasks-to-ical",
  "name": "gizza-ai/tasks-to-ical",
  "version": "0.1.0",
  "title": "Tasks to iCal — turn a todo.txt list into an .ics calendar file — gizza.ai",
  "description": "Paste a todo.txt list and get an .ics file of to-do or VEVENT entries to import into Apple Reminders, Google Calendar or Outlook. Runs in your browser.",
  "tags": [
    "todo.txt to ics",
    "tasks to ical",
    "todo to calendar",
    "vtodo generator",
    "ics task export",
    "todo.txt due date calendar",
    "import todo.txt into google calendar",
    "icalendar todo converter"
  ],
  "category": "utilities",
  "urls": {
    "page": "https://gizza.ai/tools/tasks-to-ical/",
    "markdown": "https://gizza.ai/tools/tasks-to-ical/index.md",
    "descriptor": "https://gizza.ai/tools/tasks-to-ical/tool.json",
    "deep_link_example": "https://gizza.ai/tools/tasks-to-ical/?tasks=%28A%29%20Pay%20the%20hosting%20invoice%20%2Badmin%20%40office%20due%3A2026-08-25%0ADraft%20the%20quarterly%20report%20%2Bwork%20t%3A2026-08-20%20due%3A2026-08-28%0Ax%202026-08-19%202026-08-01%20File%20the%20tax%20return%20%2Badmin%20due%3A2026-08-19&component=vtodo&include=dated&skip_completed=true&duration_minutes=60&reminder_minutes=0&timezone=floating&calendar_name=Work%20deadlines"
  },
  "cli": "gizza tool tasks-to-ical \"(A) Pay the hosting invoice +admin @office due:2026-08-25\nDraft the quarterly report +work t:2026-08-20 due:2026-08-28\nx 2026-08-19 2026-08-01 File the tax return +admin due:2026-08-19\"",
  "tool": {
    "description": "Turn a todo.txt task list into an iCalendar (.ics) file that Apple Reminders, Nextcloud Tasks, Thunderbird, Google Calendar, Outlook and anything else that speaks iCalendar can import. Paste the list into `tasks`, one task per line. Each line is read as todo.txt: a leading `x` marks it done and is followed by the completion date and then the creation date, `(A)`-`(Z)` sets priority (also accepted as a `pri:A` tag), `+project` and `@context` words become CATEGORIES, and `due:` / `t:` carry the deadline and the start (threshold) date. Dates are `due:2026-08-25` for a whole day or `due:2026-08-25T14:30` for a timed deadline. `component` picks to-do entries (default — DUE, STATUS:NEEDS-ACTION or COMPLETED, PERCENT-COMPLETE, the COMPLETED and CREATED dates) or VEVENT entries, which land on the calendar grid in apps that ignore to-do; an event runs from its `t:` date through its `due:` date as an all-day span, or for `duration_minutes` when the date is timed. `include` exports only dated tasks (default) or all of them, and `skip_completed` drops finished ones. `reminder_minutes` adds a VALARM (anchored to DUE with RELATED=END on a to-do, to the start on a VEVENT), `timezone` picks floating local times or UTC with the trailing Z, and `calendar_name` sets X-WR-CALNAME. The task text is cleaned of its priority, dates and known tags for SUMMARY while the original line is kept verbatim in DESCRIPTION, so nothing is lost; unknown `key:value` words stay in the text. UIDs come from a `uid:`/`id:` tag or are derived from the task, and DTSTAMP is fixed, so the same list always converts to the same bytes. Output is one VCALENDAR with RFC 5545 CRLF endings, 75-octet line folding and escaped text. `rec:` repeat tags are recognised and removed from the summary but NOT expanded into RRULEs — expand them first with the recurring-task-expander tool. Up to 2000 tasks per run; a task with an unreadable date, a start after its due date, or no text at all is reported by line number instead of being silently dropped.",
    "parameters": {
      "additionalProperties": false,
      "properties": {
        "calendar_name": {
          "description": "An optional display name for the whole calendar, written as X-WR-CALNAME — Google Calendar, Apple Calendar and Outlook use it to label the imported calendar instead of showing the file name. Leave it empty to write no name at all.",
          "type": "string"
        },
        "component": {
          "default": "vtodo",
          "description": "Which iCalendar component each task becomes. \"vtodo\" (default) writes to-do entries carrying DUE, STATUS and PERCENT-COMPLETE — what Apple Reminders, Nextcloud Tasks and Thunderbird import as tasks. \"vevent\" writes calendar events instead, which every calendar app shows on the grid, including Google Calendar, which ignores to-do entirely. Every task needs a date to become an event, so \"vevent\" rejects an undated task by line number rather than dropping it.",
          "enum": [
            "vtodo",
            "vevent"
          ],
          "type": "string"
        },
        "duration_minutes": {
          "default": 60,
          "description": "How long a timed calendar event lasts, in minutes, when `component` is \"vevent\" and the task's date carries a time (`due:2026-08-25T14:30`). 60 by default, 1-1440 (one day). Whole-day tasks ignore it: they span from their `t:` date through their `due:` date as an all-day event, and to-do output ignores it entirely.",
          "maximum": 1440,
          "minimum": 1,
          "type": "integer"
        },
        "include": {
          "default": "dated",
          "description": "Which tasks to export. \"dated\" (default) keeps only tasks carrying a `due:` or `t:` tag, so a working todo.txt full of someday items converts to just the deadlines. \"all\" keeps every task; undated ones become to-do entries with no DUE, which task apps show in an unscheduled list.",
          "enum": [
            "dated",
            "all"
          ],
          "type": "string"
        },
        "reminder_minutes": {
          "default": 0,
          "description": "Add a pop-up reminder this many minutes ahead of time (a VALARM with ACTION:DISPLAY and the task text as its message). 0 by default, which writes no reminder at all; up to 10080 minutes (one week) of lead time. On a to-do the trigger is anchored to the DUE date with RELATED=END, per RFC 5545; on a VEVENT it counts back from the event's start.",
          "maximum": 10080,
          "minimum": 0,
          "type": "integer"
        },
        "skip_completed": {
          "default": false,
          "description": "Leave out tasks marked done with a leading `x`. Off by default, because a completed task still exports usefully — it becomes STATUS:COMPLETED with PERCENT-COMPLETE:100 and its COMPLETED date, which is how you archive finished work into a calendar. Turn it on to export only what is still outstanding.",
          "type": "boolean"
        },
        "tasks": {
          "description": "The task list in todo.txt form, one task per line. Understood on each line: a leading `x` completion marker followed by the completion date and then the creation date, an `(A)`-`(Z)` priority (before or after the completion date, or as a `pri:A` tag), `+project` and `@context` words, and the `due:`, `t:`, `rec:`, `h:` and `uid:`/`id:` tags. Dates are `due:2026-08-25` for a whole-day deadline or `due:2026-08-25T14:30` for a timed one, with optional seconds. Blank lines and lines starting with `#` are ignored, and unknown `key:value` words stay in the task text. Up to 2000 tasks per run.",
          "type": "string"
        },
        "timezone": {
          "default": "floating",
          "description": "How the times on timed tasks are anchored. \"floating\" (default) writes them with no zone marker, so every calendar shows 14:30 as 14:30 in whatever timezone the reader is in — right for a personal deadline list. \"utc\" treats the written times as already being UTC and adds the trailing Z, so clients convert them into each person's own zone. Whole-day tasks are unaffected either way.",
          "enum": [
            "floating",
            "utc"
          ],
          "type": "string"
        }
      },
      "required": [
        "tasks"
      ],
      "type": "object"
    }
  }
}