Agent skill

task_automation

Design effective automated workflows using scheduled tasks, prompt chaining, and delivery channels.

Stars 113
Forks 16

Install this agent skill to your Project

npx add-skill https://github.com/siddsachar/Thoth/tree/main/bundled_skills/task_automation

SKILL.md

When the user wants to set up automations, create recurring workflows, schedule something, or set a reminder, apply these principles:

How Tasks Work

A task is an ordered list of prompts executed sequentially in a dedicated thread. Each step sees the full conversation history from earlier steps, so step 2 can reference, analyse, or build on the output of step 1. This is the core power — prompt chaining turns simple instructions into complex multi-turn workflows.

There are three task types:

  • Multi-step prompt tasks — the agent executes each prompt in order, accumulating context. Use for research, reports, gather-then-summarise workflows.
  • Notify-only tasks — fire a desktop/channel notification with no agent invocation. Use for simple reminders and timers.
  • One-shot timers — use delay_minutes for quick "remind me in 30 minutes" requests. These auto-delete after firing.

Prompt Chaining — The Core Pattern

  1. Chain Steps That Build on Each Other — Design prompts so each step uses the output of the previous one. Example:

    • Step 1: "Search for the latest news about AI regulation in the EU"
    • Step 2: "Now summarise the key findings from above into 5 bullet points with source links"
    • Step 3: "Draft a short email to my team highlighting the top 3 developments"

    Step 2 works because it can see step 1's search results in the conversation. Step 3 works because it can see the summary.

  2. Write Prompts Like Briefings — State the goal, specify what to check, and describe the desired format. Vague prompts produce vague results. Each prompt should make it clear what the agent should do in that step.

  3. Conditional Logic in Prompts — Write prompts that handle "nothing found" gracefully: "Check for calendar events tomorrow. If there are none, just say 'Clear schedule tomorrow.' If there are events, list them with times and highlight any conflicts."

  4. Use Template Variables{{date}}, {{day}}, {{time}}, {{month}}, {{year}} make prompts context-aware at runtime. "Summarise news for {{date}}" produces different results each day.

When to Use One Task vs. Multiple Tasks

  1. One multi-step task when the steps form a pipeline — each step needs the previous step's output. A research task that searches → reads sources → synthesises → formats is one task.
  2. Separate tasks when the workflows are independent — a morning weather check and an inbox summary don't need each other's output. Separate tasks let the user enable, disable, schedule, or deliver them independently.
  3. Morning stack pattern — For daily routines, create separate tasks for each piece (weather, news, calendar, project status). The user can toggle individual pieces on/off and schedule them at different times.

Scheduling

  1. Match the schedule to the rhythm:
    • daily:HH:MM — briefings, digests, check-ins
    • weekly:DAY:HH:MM — reviews, summaries, reports
    • interval:H / interval_minutes:M — monitoring, polling, frequent checks
    • cron:EXPR — complex schedules (e.g. cron:0 9 * * mon-fri for weekdays only)

Delivery & Notification

  1. Pick the right channel — Telegram for mobile-friendly results the user needs on the go, email for reports others need to see, desktop notification (notify_only) for simple nudges.
  2. Ask before defaulting — Don't assume a delivery channel. Ask how the user wants to receive results. Some automations are better consumed on-demand.

Advanced Features

  1. Model override — Use the model parameter to run a specific task on a different model (e.g. a heavier model for complex research, a lighter one for quick checks).
  2. Persistent threads — By default each run gets a fresh thread. For tasks that should maintain ongoing context across runs (e.g. a project status tracker that remembers prior updates), use persistent_thread_id.
  3. Skills override — Assign specific skills to a task so it runs with a tailored skill set regardless of the user's global skill settings.

Pipeline Mode (Advanced Steps)

Pipeline mode replaces simple prompt lists with typed steps for complex workflows. Use steps instead of prompts when you need conditional branching, approval gates, subtasks, or notifications.

Step Types

  • prompt — Execute an agent prompt. Supports {{prev_output}} and {{step.<id>.output}} for data passing between steps. Optional: on_error (stop/skip), max_retries, retry_delay_seconds.
  • condition — Evaluate a condition on the previous step's output and branch. Fields: condition (expression), if_true (step ID to jump to), if_false (step ID or "end"). Operators: contains:X, not_contains:X, equals:X, matches:REGEX, gt:N, lt:N, empty, not_empty, true, false, json:path:operator:value, llm:question, and:[...], or:[...].
  • approval — Pause the pipeline and wait for human approval before continuing. Fields: message, timeout_minutes (0 = wait forever, default 30). The user approves or denies from the Activity tab.
  • subtask — Run another task inline as a sub-pipeline (max depth 2). Fields: task_id, pass_output (bool, pass previous output as input).
  • notify — Send a notification without agent invocation. Fields: message, channel (desktop/telegram/email).

Choosing the Right Condition Operator

  • llm:question — Best for natural language output. An LLM evaluates the question against the previous step's output and returns yes/no. Use when the output is free-form text (e.g. llm:Were any relevant results found?). Most reliable for ambiguous output.
  • contains:X / not_contains:X — Keyword match. Good for structured output or sentinel values.
  • empty / not_empty — Only when the step literally returns nothing on failure.
  • equals:X — Exact string match. Only reliable when the prompt is engineered to output a specific sentinel value (e.g. "If no results, output exactly: NO_RESULTS").
  • json:path:operator:value — For structured JSON output with dot-path access.
  • and:[...] / or:[...] — Combine multiple operators.

Data Passing Between Steps

Each step's output is captured. Use template variables to reference it in later steps:

  • {{prev_output}} — the output of the immediately preceding step.
  • {{step.prompt_1.output}} — the output of the step with ID prompt_1.

Step IDs are auto-generated as {type}_{counter} — e.g. prompt_1, condition_1, prompt_2, notify_1. Do NOT provide an id field; it is assigned automatically based on step type and position.

Flow Control with next

All step types accept an optional next field to override the default linear advancement:

  • "next": "step_id" — jump to a specific step after this one completes.
  • "next": "end" — terminate the pipeline after this step.

This is essential for branching workflows: when a condition branches to an if_true path, the last step of that branch should use "next": "end" to prevent fall-through into the if_false path.

Safety Modes

Every task has a safety_mode that controls access to destructive tools (shell commands, file writes, emails, calendar changes):

  • block (default) — destructive tools are removed entirely. Safest for automated runs.
  • approve — destructive tools are available, but the pipeline pauses for human approval before executing them. The user approves from the Activity tab.
  • allow_all — no restrictions. Use only for trusted, well-tested pipelines.

Pipeline Step Examples

python
# Search → Condition → Branch → Approve → Notify
# Step IDs are auto-assigned: prompt_1, condition_1, notify_1, prompt_2, approval_1, notify_2
steps = [
    {"type": "prompt", "prompt": "Search for breaking news about {{topic}}"},
    {"type": "condition", "condition": "llm:Were any relevant results found?",
     "if_true": "prompt_2", "if_false": "notify_1"},
    {"type": "notify", "message": "No results for {{topic}}.", "channel": "desktop",
     "next": "end"},
    {"type": "prompt", "prompt": "Summarize: {{step.prompt_1.output}}"},
    {"type": "approval", "message": "Send this summary to the team?"},
    {"type": "notify", "message": "{{step.prompt_2.output}}", "channel": "telegram"},
]

Key patterns in this example:

  • llm: condition operator for intelligent evaluation of free-text search output
  • notify_1 has "next": "end" to stop the pipeline after the "no results" branch — without this, execution would fall through into prompt_2
  • if_true jumps to prompt_2, skipping the "no results" notify
  • Approval gate before sending via Telegram

When to Use Pipeline vs. Simple Prompts

  • Simple prompts for linear workflows where each step just needs conversation context.
  • Pipeline steps when you need: branching logic, approval gates before destructive actions, reusable subtask composition, explicit data routing between steps, or per-step error handling.

Maintenance

  1. Check first — Before creating a new task, check task_list to avoid duplicates or overlapping schedules.
  2. Test immediately — Always suggest task_run_now after creation so the user can verify the output before waiting for the first scheduled run.
  3. Iterate prompts — If the output isn't right, update the prompts with task_update rather than deleting and recreating.

Monitoring / Polling

When the user wants to monitor a condition and be notified when it changes ("check X and tell me when Y", "alert me if Z drops below W"), use the interval + self-disable pattern:

  1. Use an interval scheduleinterval_minutes:M for frequent checks (stock availability, price drops) or interval:H for slower checks (daily digest changes).

  2. Write a conditional prompt — The prompt should:

    • Check the condition (e.g. search the web, read a URL, check a price)
    • If the condition IS met → report the finding and self-disable with task_update(task_id='{{task_id}}', enabled=false)
    • If the condition is NOT met → say so briefly (this keeps the persistent thread informed without wasting tokens)
  3. Always use persistent_thread_id — This lets the agent see prior checks across runs. Essential for "notify me if the price drops below X" (needs to compare to last check) or "tell me when there's a new version" (needs to know the old version).

  4. Template: polling prompt pattern

    Search for [condition]. If [success criteria], report your findings
    and call task_update(task_id='{{task_id}}', enabled=false) to stop
    this monitor. If [condition not met], say '[thing] not yet
    available as of {{time}} — will check again.'
    
  5. Self-disable, don't self-delete — Background tasks cannot delete themselves (safety restriction). Use task_update(enabled=false) instead. The user can re-enable, delete, or leave the disabled task.

Expand your agent's capabilities with these related and highly-rated skills.

Didn't find tool you were looking for?

Be as detailed as possible for better results