process-delegate-tasks
Automate the full lifecycle of every URL-based task in the "Delegate" list:
- Pick up the task from Google Tasks
- Detect the URL type (Threads post or YouTube video)
- Fetch or transcribe the content
- Summarize in Traditional Chinese with the raw content appended verbatim
- Save a report
- Mark the task done
Two URL types are handled:
| URL Type | Trigger | Processing |
|---|---|---|
| Threads post | threads.net or threads.com |
fetch-threads-post skill → synchronous |
| YouTube video | youtube.com or youtu.be |
yt2doc Docker → background (async) |
DO NOT STOP after processing a single task. This skill clears the entire backlog. The workflow is idempotent — skipping tasks already completed or lacking a supported URL ensures safe re-runs.
Prerequisites
gwsCLI installed and authenticated (gws auth loginif needed)agent-browserinstalled (for Threads tasks)- Docker running (for YouTube tasks) — verify with
docker info - For all Google Tasks API calls, refer to
../gws-tasks/SKILL.md
Procedure
Step 1 — Discover the "Delegate" task list
The list ID can change, so always resolve it by name:
gws tasks tasklists list
Parse the JSON and find the item where title == "Delegate". Extract its id. If the list doesn't exist, stop and tell the user.
Step 2 — Fetch incomplete tasks
gws tasks tasks list \
--params '{"tasklist": "<DELEGATE_LIST_ID>", "showCompleted": false, "maxResults": 100}'
This returns only tasks with status == "needsAction". If items is empty or missing, the list is clear — tell the user.
Step 3 — Classify each task
For each task, scan these fields for a URL: title, links[].link, links[].description, notes.
| URL contains | Task type | Action |
|---|---|---|
threads.net or threads.com |
Threads task | Queue for Threads flow |
youtube.com or youtu.be |
YouTube task | Queue for YouTube flow |
| Neither | Unrecognised | Skip — log: "Skipping '<title>': no supported URL" |
Extract the first matching URL from each task. Build two separate queues: threads_queue and youtube_queue.
Async Strategy
Because YouTube transcription takes 5–80 minutes, use a fire-and-poll approach:
- Fire — launch all YouTube background jobs first (Step 4Y)
- Process — immediately handle all Threads tasks synchronously (Steps 4T–7T)
- Poll — once Threads tasks are done, poll each YouTube job until complete (Steps 5Y–7Y)
This means a 45-minute video never blocks five Threads tasks from finishing.
Threads Flow (Steps 4T–7T)
Step 4T — Fetch the Threads post content
For each task in threads_queue, follow the full procedure defined in fetch-threads-post:
📄 Read and follow
.agents/skills/fetch-threads-post/SKILL.md
Use a unique session name per task to avoid state collisions:
agent-browser --session delegate-task-<task-id> open "<THREADS_URL>"
# ... follow fetch-threads-post procedure to expand and extract content ...
agent-browser --session delegate-task-<task-id> close
CRITICAL: Ensure the post is fully expanded (click "Read more") and captured entirely. Truncated raw content is unacceptable.
- Scroll first: Run
agent-browser --session delegate-task-<task-id> scroll down 1000to trigger lazy-loading and move past overlays. - Extract body: Use
agent-browser --session delegate-task-<task-id> get text bodyas the primary extraction method for the📄 原始內容section.
Step 5T — Verify and generate a Traditional Chinese summary
Verification first: Compare extracted text length against the visible post. If the raw content appears cut off mid-sentence, repeat extraction with get text body.
Produce a summary in Traditional Chinese (繁體中文):
- 零幻覺(Zero Hallucination): Only summarize what is in the post. No inference or extrapolation.
- 全面性(Comprehensiveness): Include all key points — don't drop information for brevity.
- 客觀性(Objectivity): Neutral tone, no personal commentary.
Step 6T — Save the Threads report
Output directory: reports/Threads_YYYY_MM_DD/ (today's date).
Filename: Derived from author handle + topic. Strip invalid path characters (/, ?, =, &, spaces → _).
@cooljerrett + topic "AI productivity" → cooljerrett_AI_productivity.md
Write the report using the Threads 報告格式 defined in assets/output_template.md.
🎯 產生「AI 分析」區塊前,必須遵照
assets/output_template.md中的指示讀取data/goals.md與data/user_preferences.md(若存在)。
Confirm the file is written before proceeding.
Step 6Tb — Append suggestion to pending backlog
Append the AI analysis suggestion from this report to data/suggestions_pending.md:
---
### YYYY-MM-DD | Threads | [@{handle} — {topic}]({threads_url})
- 🏷️ {分類} | 💎 {價值評分} | ⚡ {可行動性} | 🎯 {決策建議}
- 📋 建議:{建議下一步}
- 📄 [報告](file:///absolute/path/to/report.md)
If data/suggestions_pending.md doesn't exist, create it with the # 📋 Pending Suggestions heading first.
Step 7T — Mark the Threads task as completed
gws tasks tasks patch \
--params '{"tasklist": "<DELEGATE_LIST_ID>", "task": "<TASK_ID>"}' \
--json '{"status": "completed"}'
Log: "✅ Task '<title>' marked as completed. Report saved to reports/Threads_YYYY_MM_DD/<filename>.md"
YouTube Flow (Steps 4Y–7Y)
Step 4Y — Launch YouTube background job
For each task in youtube_queue, apply the Video Strategist from yt2doc:
📄 Read the Video Strategist table in
.agents/skills/yt2doc/SKILL.md(Step 2)
| Video Duration | Whisper Model | Est. Time | Min Docker RAM |
|---|---|---|---|
| < 30 min | medium |
5–10 min | 4 GB |
| 30–60 min | small |
10–20 min | 6 GB |
| 1–2 hours | small |
35–55 min | 8 GB |
| > 2 hours | base |
50–80 min | 10 GB |
If duration is unknown, look it up via web search or yt-dlp --print duration_string. Default to the conservative path when uncertain.
Create the output directory and launch in the background (use run_command with WaitMsBeforeAsync=5000, then poll with command_status):
mkdir -p reports/YouTube_YYYY_MM_DD
docker run --rm \
-v "$(pwd)/reports/YouTube_YYYY_MM_DD:/output" \
ghcr.io/shun-liang/yt2doc \
--video "<YouTube URL>" \
--output /output/<video_id>.md \
--whisper-model <model> \
--add-table-of-contents
Tell the user what's happening:
"Launching yt2doc for
<url>using the<model>model (~X–Y minutes). Running in the background while I process Threads tasks."
Store the job metadata in-memory: { task_id, youtube_url, command_id, output_path, model }.
Docker not running? Skip this task with a warning: "⚠️ Skipping YouTube task '<title>': Docker is not running." Continue with remaining tasks.
Step 5Y — Poll for YouTube job completion
After all Threads tasks are done, poll each YouTube command_id:
command_status(command_id, WaitDurationSeconds=60) # repeat until DONE
While polling, periodically report elapsed time to the user:
"Still transcribing
<title>… (N minutes elapsed)."
On completion, check the exit code:
- Exit code 0 → proceed to Step 6Y
- Exit code 137 (OOM) → report:
"⚠️ Task '<title>' FAILED: Docker ran out of memory. Increase Docker RAM: Docker Desktop → Settings → Resources → Advanced → Memory (8 GB minimum, 12 GB recommended)."Do not mark the task as done. - Other non-zero → show last 20 lines of stderr. Do not mark the task as done.
Step 6Y — Generate the YouTube report
Once the yt2doc output file is confirmed non-empty:
- Read the full transcript file content
- Extract: video title (first
#heading), chapter count, approximate character count - Generate a Traditional Chinese summary from the transcript content following the same quality rules as the Threads flow (Zero Hallucination, Comprehensiveness, Objectivity)
- Write the report using the YouTube 影片報告格式 defined in
assets/output_template.md.
🎯 產生「AI 分析」區塊前,必須遵照
assets/output_template.md中的指示讀取data/goals.md與data/user_preferences.md(若存在)。
Confirm the file is written before proceeding.
Step 6Yb — Append suggestion to pending backlog
Append the AI analysis suggestion from this report to data/suggestions_pending.md:
---
### YYYY-MM-DD | YouTube | [{Video Title}]({youtube_url})
- 🏷️ {分類} | 💎 {價值評分} | ⚡ {可行動性} | 🎯 {決策建議}
- 📋 建議:{建議下一步}
- 📄 [報告](file:///absolute/path/to/report.md)
If data/suggestions_pending.md doesn't exist, create it with the # 📋 Pending Suggestions heading first.
Step 7Y — Mark the YouTube task as completed and cleanup
# Mark as completed
gws tasks tasks patch \
--params '{"tasklist": "<DELEGATE_LIST_ID>", "task": "<TASK_ID>"}' \
--json '{"status": "completed"}'
# Remove the intermediate raw transcription file (already included in the final report)
rm "/Users/allanbian/my-ai-workflow/reports/YouTube_YYYY_MM_DD/<video_id>.md"
Log: "✅ Task '<title>' marked as completed. Report saved to reports/YouTube_YYYY_MM_DD/<filename>.md. Intermediate file removed."
Step 8 — Final Summary
After all queues are processed, output a unified summary:
Processed X Threads task(s):
✅ @handle1 — topic → reports/Threads_2026_04_29/filename1.md
✅ @handle2 — topic → reports/Threads_2026_04_29/filename2.md
Processed Y YouTube task(s):
✅ Video Title → reports/YouTube_2026_04_29/video_id.md
⚠️ Another Video → FAILED (OOM — increase Docker RAM to 8 GB)
Skipped Z task(s) (no supported URL):
— "Buy groceries"
— "Call dentist"
Step 9 — Ephemeral Cleanup
Once the entire backlog is cleared, delete all temporary diagnostic files created during the session:
- Screenshots (
*.png) - Temporary scratch files or ID lists (
*.txt,*.jsongenerated for the task) - Any debug logs outside
reports/
Log: "🧹 Session cleanup complete: removed temporary diagnostic files."
Troubleshooting
Task list not found: Run gws tasks tasklists list and confirm "Delegate" exists.
Threads URL behind login wall: Follow the authenticated access section in fetch-threads-post/SKILL.md.
gws tasks tasks patch fails: Double-check tasklist and task are IDs (not titles). The task ID comes from the id field in the tasks list response.
YouTube — Exit code 137 (OOM): Increase Docker RAM: Docker Desktop → Settings → Resources → Advanced → Memory (8 GB minimum, 12 GB recommended). Retry with --whisper-model base if RAM is still constrained.
YouTube — LLMModelNotSpecified error: Do NOT use --segment-unchaptered unless you also have a local Ollama running. Remove that flag.
YouTube — ChunkedEncodingError: Network interruption during model download — retry the same command; it resumes from cache.
URL contains & in shell: Always wrap URLs in quotes.
Anti-Truncation Standard (Threads)
- Click "Read more" if visible.
- Scroll down mandatory: Always run
scroll down 1000before extraction to trigger lazy-loading of long posts and masked content. - Use
get text body: Always useget text bodyas the primary extraction method to capture content behind modals or overlays. - Manual check: A complete post usually ends with a footer, signature, or engagement metrics. If the text ends abruptly, it is likely truncated.
- No summarization of Raw Content: The
📄 原始內容section MUST contain verbatim extraction — never summarize or omit parts.