一键导入
fill-tempo-meetings
Backfill missing Tempo meeting worklogs from a user-provided start date.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Backfill missing Tempo meeting worklogs from a user-provided start date.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
| name | fill-tempo-meetings |
| description | Backfill missing Tempo meeting worklogs from a user-provided start date. |
Backfill missing Tempo worklogs for calendar meetings from a start date.
This skill logs only meetings from the user's Outlook ICS calendar. It logs every valid meeting under TEMPO_MEETING_TICKET.
Calendar meetings are the authoritative source for meeting worklogs. If a past workday has valid meetings, log those meeting durations under the configured meeting ticket. Existing non-meeting Tempo worklogs must not block meetings; move or shorten them when needed so meeting records occupy their real calendar windows and the day remains safely capped at 8h.
Required env vars:
| Variable | Description |
|---|---|
TEMPO_API_TOKEN | Tempo REST API token |
TEMPO_MEETING_TICKET | Jira ticket key to log meetings under, e.g. AB-1234 |
JIRA_API_TOKEN | Jira/Atlassian API token, used only to resolve the meeting ticket issue ID |
JIRA_ORG | Jira organization slug, e.g. my-company for https://my-company.atlassian.net |
JIRA_EMAIL | Jira account email address |
OUTLOOK_ICS_URL | Outlook published ICS calendar URL |
Verify them; if any are missing, tell the user to export them and stop:
for var in TEMPO_API_TOKEN JIRA_ORG JIRA_EMAIL JIRA_API_TOKEN TEMPO_MEETING_TICKET OUTLOOK_ICS_URL; do
if [ -z "${!var}" ]; then echo "MISSING: $var"; fi
done
JIRA_URL="https://${JIRA_ORG}.atlassian.net"
One arg: a start date the user typed in any reasonable form. Normalize it to YYYY-MM-DD before doing anything else, using the current local date for missing parts:
| User input | Resolves to |
|---|---|
2026-04-01 | 2026-04-01 |
april 1 / apr 1 | April 1st of the current year |
1 april / 01.04 | Same - April 1st of the current year |
april 2026 | April 1st, 2026 (missing day → 1st) |
january | January 1st of the current year (missing day → 1st, missing year → now) |
2026 | January 1st, 2026 |
04/01/2026 | Treat as YYYY-MM-DD if year first; otherwise assume DD/MM/YYYY (EU). |
last monday, 3 weeks ago | Resolve relative to today. |
Rules:
-, /, ., or spaces as separators.Start date must be before today. and stop.Usage: /fill-tempo-meetings <date> - examples: /fill-tempo-meetings 2026-04-01, /fill-tempo-meetings "april 1", /fill-tempo-meetings "january 2026" and stop.After normalization, build the workday list (Mon–Fri only) from the start date through yesterday, inclusive. Never include today - today's hours aren't done yet, so this skill must not touch them.
Steps 2a–2d are independent. Fire all four requests concurrently (background & + wait, or async client) - do not run them serially.
2a. Tempo worker ID:
curl -s -u "${JIRA_EMAIL}:${JIRA_API_TOKEN}" "${JIRA_URL}/rest/api/3/myself" > /tmp/myself.json &
2b. Outlook ICS (only call to OUTLOOK_ICS_URL):
curl -s "${OUTLOOK_ICS_URL}" -o /tmp/outlook_calendar.ics &
2c. Meeting Jira issue ID:
curl -s -u "${JIRA_EMAIL}:${JIRA_API_TOKEN}" \
"${JIRA_URL}/rest/api/3/issue/${TEMPO_MEETING_TICKET}?fields=id" > /tmp/issue.json &
2d. Existing Tempo worklogs for the full date range (paginate via offset if >1000):
curl -s -H "Authorization: Bearer ${TEMPO_API_TOKEN}" \
"https://api.tempo.io/4/worklogs/user/${TEMPO_WORKER_ID_PLACEHOLDER}?from=<START_DATE>&to=<END_DATE>&limit=1000" > /tmp/worklogs.json &
Note: 2d depends on the worker ID from 2a. To keep parallelism, either (a) run 2a–2c in parallel first, then 2d, or (b) defer worker ID by using the myself call's accountId once 2a returns, while 2b/2c are still in flight.
wait. Then:
BEGIN:VCALENDAR; fail fast otherwise.startDate. Per date compute total logged seconds, logged issue IDs, occupied windows (startTime + duration), and the full payload fields needed for later PUT calls (issue.id, startDate, startTime, description, author.accountId, tempoWorklogId, timeSpentSeconds).Reuse this in-memory worklog snapshot for all downstream logic. Do not re-GET individual worklogs before PUT - the Step 2d response has every field needed for the update body.
Use existing worklogs to detect already-logged meetings, occupied windows, and total daily time. Existing meeting worklogs on TEMPO_MEETING_TICKET may cover meetings and should prevent duplicates. Existing non-meeting worklogs are movable/resizable when they conflict with valid meetings or when the day would exceed 8h after adding meetings.
From /tmp/outlook_calendar.ics, extract VEVENTs occurring on the target date. Pull at least:
SUMMARYDTSTARTDTENDSTATUSMETHODATTENDEE;PARTSTAT, when presentUIDRECURRENCE-IDEXDATERRULESkip the event if any of these are true:
STATUS:CANCELLED.METHOD:CANCEL.SUMMARY starts with Canceled: or Cancelled: (case-insensitive) - Outlook flags some cancellations only via the summary prefix, not STATUS.ATTENDEE line has PARTSTAT=DECLINED.DATE-only DTSTART).SUMMARY matches a non-work keyword, case-insensitive: lunch, breakfast, dinner, gym, doctor, dentist, break, pick up, drop off, personal, errand, school, commute, vacation, holiday.When unsure whether an event is personal/non-work, skip it.
Honor recurrence enough to avoid false logs:
EXDATE for recurring series.RECURRENCE-ID.STATUS:CANCELLED cancels only that occurrence.FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FRFREQ=WEEKLY;BYDAY=THBYDAY combinationFREQ=DAILYConvert DTSTART/DTEND to the user's local timezone and use local HH:MM for Tempo startTime.
For each valid meeting candidate:
TEMPO_MEETING_TICKET / TEMPO_MEETING_ISSUE_ID.TEMPO_MEETING_TICKET already appears to cover the same meeting time or duration.Existing non-meeting Tempo worklogs must not cause a meeting to be skipped. Selected meeting windows are fixed and authoritative. Move or shorten existing non-meeting worklogs when needed so meetings occupy their real calendar times.
Use Tempo update APIs for existing non-meeting worklogs only when required. Never delete records.
For each date:
TEMPO_MEETING_TICKET as fixed; use them to avoid duplicate meeting logs.Every Tempo record must be at least 30 minutes.
Weekends are not in the workday list. If encountered defensively:
⏭️ <DATE> - weekend, skipping.
If no valid meetings remain after duplicate detection:
⏭️ <DATE> (<Day>) - no meetings to log.
Before posting new meeting logs, update existing non-meeting records that conflict with selected meeting windows or push the day over 8h.
For moved records:
startTime unless a duration reduction is also required.For shortened records:
timeSpentSeconds only in 30-minute increments.TEMPO_MEETING_TICKET.Use Tempo's worklog update endpoint (PUT /4/worklogs/{tempoWorklogId}) for each changed record. Build the PUT body directly from the Step 2d snapshot - do not issue a fresh GET per worklog. If an update fails, do not post a meeting into an overlapping slot; mark the day partial and continue.
Each meeting becomes exactly one Tempo worklog:
issueId: TEMPO_MEETING_ISSUE_IDstartDate: target datestartTime: meeting local start time, HH:MM:SStimeSpentSeconds: actual meeting duration in secondsdescription: meeting summary, or Meeting if summary is blankauthorAccountId / worker field: TEMPO_WORKER_ID, according to Tempo API requirementsTempo has no bulk API. After all per-day plans (adjustments + new meeting POSTs) are computed, fire the entire batch concurrently across all dates at once - do not serialize per record and do not wait between days.
# adjustments first (PUTs), then meeting creates (POSTs), all in parallel
for body in "${PUT_BODIES[@]}"; do
curl -s -X PUT "https://api.tempo.io/4/worklogs/${id}" \
-H "Authorization: Bearer ${TEMPO_API_TOKEN}" \
-H "Content-Type: application/json" \
-d "$body" > "/tmp/resp_put_${id}.json" &
done
for body in "${POST_BODIES[@]}"; do
curl -s -X POST "https://api.tempo.io/4/worklogs" \
-H "Authorization: Bearer ${TEMPO_API_TOKEN}" \
-H "Content-Type: application/json" \
-d "$body" > "/tmp/resp_post_${i}.json" &
done
wait
Capture each response to a file (or array) keyed by record ID/index so per-day results can be aggregated after wait. If a PUT (adjustment) fails for a date, drop the meeting that needed that adjustment, mark the day partial, and continue. If a POST fails, mark only that meeting failed; do not retry inside the run.
Equivalent in a single Python script: use asyncio + aiohttp or concurrent.futures.ThreadPoolExecutor(max_workers=16) and submit every adjustment + meeting at once. Do not call subprocess.run(['curl', ...]) in a serial Python loop - that defeats parallelism.
✅ <DATE> (<Day>) - <N> meeting records, <H>h <M>m logged, <A> existing records adjusted.
⚠️ <DATE> (<Day>) - partial, <H>h <M>m logged (<reason>).
🏁 fill-tempo-meetings complete
─────────────────────────────────
Backfilled: 15 days
Meeting records: 42
Adjusted existing: 8 records
Skipped: 4 weekends, 6 no meetings, 3 already covered
Partial/error: 1 day
Total meeting time: 38h 30m
─────────────────────────────────
Include: backfilled days, meeting records created, existing records adjusted, weekends skipped, days with no meetings, meetings skipped as already covered, partial/error days, and total logged meeting time.
TEMPO_MEETING_TICKET.STATUS:CANCELLED, METHOD:CANCEL, cancelled recurrence overrides).PARTSTAT=DECLINED).This logs past meetings from the Outlook ICS calendar under the configured Tempo meeting ticket.
generate QA test cases from a jira ticket, github pr, free text, conversation, or any mix of context sources.
analyze a feature context (PR, Jira ticket, Confluence page, URL, free text, or current conversation) and produce AC bullet points for QA.
Log time records to Jira Tempo with automatic calendar meeting integration
generate a jira bug ticket title and description from the current conversation.
deep, harsh code review of a github pull request by number or branch name.
fetch a jira ticket and produce a detailed implementation guide based on the current codebase.