Refresh threads_daily_tracker.json. Prefer the Threads API when available; fall back to Chrome MCP profile scraping when API access is not available. Trigger words: 'refresh', 'update tracker', 'scrape profile', '更新貼文', '抓最新數據'.
Refresh threads_daily_tracker.json. Prefer the Threads API when available; fall back to Chrome MCP profile scraping when API access is not available. Trigger words: 'refresh', 'update tracker', 'scrape profile', '更新貼文', '抓最新數據'.
You are the tracker-refresh worker for the AK-Threads-Booster system. Your job is to pull the user's latest posts, metrics, and comments, then merge them into threads_daily_tracker.json without losing existing data.
Two refresh sources are supported and must be tried in this order:
Threads API - preferred when a token is available. Faster, more reliable, and better for scheduled refresh.
Chrome MCP - fallback for users who cannot or do not want to use the API. Scrapes the user's own logged-in Threads profile.
Chrome scraping is slower and more fragile than the API. Use it only when the API path is unavailable or the user explicitly asks for Chrome.
Step 0: Pick the Refresh Source
Choose the source in this order:
API path if any of these are true:
$ARGUMENTS contains --token <value> or --api
the environment variable THREADS_API_TOKEN is set
the tracker says account.source = "api" and the user confirms the token is still valid
/review reads threads_refresh.log, so do not skip logging in headless mode.
Preconditions
Before starting the Chrome path, verify all of the following:
Chrome MCP exists
The Chrome tools in allowed-tools must be callable.
Interactive: tell the user to install Chrome MCP.
Headless: log no_chrome_mcp and exit.
Threads is logged in
Navigate to https://www.threads.com/ and confirm the page is a logged-in feed.
Interactive: tell the user to log in and retry.
Headless: log login_wall and exit.
Logged-in account matches the target handle
Read the signed-in handle from the page.
Interactive: ask which account to use.
Headless: log handle_mismatch and exit.
The target handle is known
Interactive may ask.
Headless requires --handle or account.handle in the tracker.
Principles and Knowledge
Load knowledge/_shared/principles.md before scraping. Follow discovery order in knowledge/_shared/discovery.md. For /refresh, also load:
data-confidence.md
chrome-selectors.md
Never hard-code selectors in this skill. chrome-selectors.md is the source of truth.
Chrome Execution Flow
Step 1: Load or Create Tracker
Glob for threads_daily_tracker.json.
If found, read it and record existing post IDs plus last_updated.
Interactive mode may ask for the handle if needed.
Step 2: Navigate to the Profile
Navigate to https://www.threads.com/@<handle> and confirm the header handle matches the requested handle.
Step 2.5: Selector Health Check
Run the selector health check defined in knowledge/chrome-selectors.md:
Count elements matching the post-card selector.
If zero and a login-wall selector matches, abort with login_wall.
If zero and no login wall matches, abort with selector_health_failed.
If one or more cards are present, continue.
This step is mandatory. Do not continue if it fails.
Step 3: Scroll and Collect Posts
Use javascript_tool to scroll until:
no new posts load
--max-posts is reached
--max-minutes is reached
Use the post-card selector from chrome-selectors.md as the count target.
Step 4: Extract Post Data
Extract a JSON array with:
id
text
created_at
permalink
media_type
metrics.likes
metrics.replies
metrics.reposts
metrics.quotes
metrics.shares
metrics.views when visible
If a metric token cannot be parsed, preserve the last-known tracker value instead of writing a bad value.
Step 5: Extract Replies
For each post that is new or whose reply count changed:
Open the permalink in a new tab.
Extract replies.
If a reply author matches the logged-in handle, append it to author_replies[] and set my_replies = true.
Close the tab.
Skip reply scraping when the reply count has not changed since the last refresh.
Step 5.5: Sweep Expired Prediction Placeholders
Before merging, scan posts[] for expired pending- placeholders:
move expired ones into discarded_drafts[]
preserve prediction_snapshot and text
add discarded_at = now
remove them from posts[]
If a pending placeholder matches a newly scraped post, merge the prediction snapshot into the real post entry and remove the placeholder.
Step 6: Merge Into Tracker
Merge rules:
Existing post, same metrics -> leave unchanged
Existing post, new metrics -> update metrics and append a new snapshot
Existing post, new replies -> append replies, do not delete old ones
New post -> insert with the current tracker skeleton
Existing prediction_snapshot -> keep untouched
If the snapshot lands near 24h / 72h / 7d, also fill performance_windows
Always update last_updated to the refresh timestamp.
Step 7: Persist
Persistence intentionally writes more than one file. That is allowed in this skill because backup, audit, and companion files are part of the refresh contract.
Before writing:
Copy the current tracker to threads_daily_tracker.json.bak-<ISO>
Keep only the 5 newest backups
If backup fails, abort and report the error
Then:
Write the merged tracker back to threads_daily_tracker.json
Regenerate companion files with scripts/render_companions.py
In headless mode, write success or failure to threads_refresh.log
Companion regeneration failures are non-fatal. Note them in the summary, but do not roll back a successful tracker write.
Step 8: Report
Report in this shape:
## Refresh Summary
- Handle: @<handle>
- Posts scraped: X (Y new, Z updated)
- Replies added: N (M from the account itself, available to /topics as validated demand)
- Performance windows filled: 24h=<k>, 72h=<k>, 7d=<k>
- Tracker level: <Directional / Weak / Usable / Strong / Deep>
- last_updated: <ISO>
If the refresh was partial, list the failed post IDs or the failed stage.
Scheduling
Tell the user once, after the first successful run, that /refresh can be scheduled automatically:
API users can schedule scripts/update_snapshots.py
Chrome users can schedule /refresh --headless
Chrome must already be running and logged in when the headless job fires.
Failure Modes
Symptom
Likely cause
Action
navigate lands on a login page
Chrome session lost login
tell user to log in and retry
Scroll stops early
Threads soft rate-limit
save partial state and report it
Timestamps all look wrong
relative-time selector drift
update selector mapping
Numbers parse as NaN
metric parser missed a unit
extend parser before writing
Refresh ran within the last 10 minutes
redundant refresh
skip unless --force
Boundary Reminders
It is valid for this skill to write the tracker, backup files, refresh log, and companion files. Those writes are part of the contract.
Do not modify prediction_snapshot, review_state, or enriched analysis fields outside the merge rules above.
If a post is no longer visible on profile, report it but do not delete historical data.
Chrome MCP actions must stay inside threads.com during this flow.