New to Kestra?
Use blueprints to kickstart your first workflows.
Delete stale Todoist tasks older than 90 days with Kestra. A confirm input gates the sweep, Loop deletes each task, and Slack gets the audit count.
Every task list accumulates a guilt layer: items created a quarter ago that will never be done and only add noise. This blueprint performs list bankruptcy as a supervised, audited flow. A Todoist filter query matches tasks created more than 90 days ago, a Loop deletes each one through io.kestra.plugin.todoist.DeleteTask, and the whole thing is gated by a boolean confirm input: when it is false, the flow fails immediately with a message demanding explicit confirmation, and nothing is listed or deleted.
require_confirmation (io.kestra.plugin.core.flow.If) checks the confirm input. When it is false, the nested io.kestra.plugin.core.execution.Fail task stops the execution with an instructive error before any Todoist call is made.list_stale (io.kestra.plugin.todoist.ListTasks) runs the Todoist filter query created before: -90 days with fetchType: FETCH. The matches are exposed as {{ outputs.list_stale.rows }} and the count as {{ outputs.list_stale.size }}. Adjust the window by editing the filter string.loop_tasks (io.kestra.plugin.core.flow.Loop) iterates over the rows, and delete_task removes each task by fromJson(item.value).id. Deletion is permanent, which is exactly why the guard exists.audit posts the deleted count to Slack, and the errors block reports both real failures and the intentional refusal when confirmation is missing.Schedule runs on the first of the month. With the default confirm: false it fails at the guard on purpose, turning the schedule into a monthly reminder that a human must re-run with confirm: true.created before: filter, tunable to any window.A cleanup script with a delete loop is one typo away from disaster and leaves no trace. Kestra adds the guard rail as a first-class flow structure, records every execution including refused ones, isolates each deletion, and posts an audit trail to Slack, all without writing a line of imperative code.
created before: -90 days filter uses Todoist's filter query syntax; verify it returns what you expect in the Todoist app before enabling deletions.TODOIST_API_TOKEN: Todoist personal API token.SLACK_WEBHOOK_URL: Slack incoming webhook URL.created before: -90 days in Todoist to preview exactly what would be deleted.confirm: false and watch it refuse, then re-run with confirm: true on a test account or narrow project.disabled: false on the monthly trigger if you want the monthly reminder behavior.projectId to list_stale, a safer default for a first rollout.io.kestra.plugin.todoist.UpdateTask and demote instead of delete.{{ outputs.list_stale.rows }} to storage before deleting, creating a recoverable archive of what was swept.