一键导入
collect-my-activity
Collect the user's daily work activity from Slack, Jira, Confluence, GitHub, and Google Drive with source links
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Collect the user's daily work activity from Slack, Jira, Confluence, GitHub, and Google Drive with source links
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Definitive reference for how Claude Code works — disambiguates skills vs hooks vs subagents vs MCPs vs slash commands vs memory vs settings. Use when asked "how does Claude Code X work", "what's the difference between X and Y", "where should this live", "build me a [skill|hook|agent|mcp|slash command]", "configure Claude Code", or when picking the right surface for a new capability.
Scribe — the project-documentation skill. Generate or maintain a project's Claude-facing documentation (CLAUDE.md, .claude/docs/*, project-context.md, README) from verified facts. Use when the user says "document this project", "write the docs for X", "the docs are stale", "fill in the .claude docs", or "/scribe". Detects existing doc state and routes between from-scratch and update. Verify-before-assert is the core discipline — confirmed facts go to committed docs, inferred/uncertain ones go to a separate hazards artifact, never silently into the repo.
Speak content aloud via Kokoro neural TTS (local, offline). Use when the user says "read it for me", "read it to me", "play it in audio", "say it", "speak it", "read that aloud", "/say-it", or asks to hear something spoken instead of reading it.
Install a local neural voice interface for Claude Code on macOS Apple Silicon. Wires mlx-whisper (STT) + Kokoro TTS (offline neural voices) into voice-claude and vtranscribe CLI scripts. Two voice contexts — personal (af_heart) and tech (af_bella). Multi-session safe — concurrent sessions speak in turn (global lock) and announce their name. No cloud APIs, no API keys.
Collect a team member's daily work activity from Slack, Jira, Confluence, and GitHub
Initialise a workspace, register projects under it, or sync upstream changes. Single entry point for workspace lifecycle.
| name | collect-my-activity |
| description | Collect the user's daily work activity from Slack, Jira, Confluence, GitHub, and Google Drive with source links |
| user_invocable | true |
| args | Optional date or date range (e.g., '2026-04-11', '2026-04-07 to 2026-04-11'). Defaults to today. |
Collect the user's work activity for a given day (or date range) from all available data sources (Slack, Jira, Confluence, GitHub, Google Drive). Every item must include a source link. Output is written to <workspace>/collected/.
Setup — Resolve <workspace>: The skill's base directory is <workspace>/.claude/skills/collect-my-activity/; walk up three directory levels and validate that <workspace>/.claude/.workspace exists. Use this <workspace> for all path references below (identity, output). Abort with a setup-broken error if validation fails — this is not recoverable from inside the skill.
Pre-flight checks: Verify the environment before collecting:
mcp__<server>__slack_search_public_and_private) and may be deferred — registered by name but schema-unloaded until fetched. Three states, not two: (a) the tools are available → proceed; (b) only an authenticate/complete_authentication tool is present → the server is a claude.ai connector awaiting interactive sign-in, so ask the user to run /mcp, select the Slack connector, and authenticate, then continue — this is recoverable, do not fail; (c) genuinely absent → fail (see below).mcp__<server>__getJiraIssue) and may be deferred — registered by name but schema-unloaded until fetched. Three states, not two: (a) the tools are available → proceed; (b) only an authenticate/complete_authentication tool is present → the server is a claude.ai connector awaiting interactive sign-in, so ask the user to run /mcp, select the Atlassian connector, and authenticate, then continue — this is recoverable, do not fail; (c) genuinely absent → fail (see below).gh CLI: Check if gh is available (which gh). Expected but not blocking. If missing, log a warning via /log (status=WARNING detail=gh CLI not available — GitHub data will be missing. Install with: brew install gh && gh auth login), mark as a gap, and continue.If Slack or Atlassian MCP is missing, stop and write a failure status:
# My Activity: YYYY-MM-DD
## Status: FAILED
**Reason**: [which MCP servers were unavailable]
Also invoke /log to record the failure (see Logging section below).
Resolve identity — MCP first, identity.md as cache, user input as last fallback:
General principle: always probe the connected MCPs for any platform-derived value before reading identity.md, and only ask the user when both fail. identity.md is a cache, not a gate.
slack_read_user_profileatlassianUserInfogetAccessibleAtlassianResources (returns the cloudId for accessible Atlassian sites)atlassianUserInfo.email (primary — works for any engineering shop with Jira/Confluence access).slack_read_user_profile.profile.email (fallback if Atlassian is unavailable).mcp__claude_ai_Google_Drive__list_recent_files → owners[0].emailAddress (last automated fallback; only works if the user owns at least one file).gh supports multiple authenticated accounts. The skill targets the cached business handle without modifying the active session (see step 4 GitHub section for the script-file token-fetch pattern). Resolve as follows:
## Profile, use it. Verify it's still authenticated via gh auth status (parse for Logged in to github.com account <handle>). If the cached handle isn't in gh auth status, fail loud (FAILED) with re-auth instructions: gh auth login --hostname github.com.gh auth status for Logged in to github.com account <handle> lines:
gh api user --jq .login, write back to ## Profile.gh accounts detected. Set GitHub username manually in <workspace>/me/identity.md ## Profile before re-running. Agents cannot disambiguate which is the business account."Write-back rule: when MCP resolves a field that is missing from identity.md's ## Profile section, append it there. Fill missing only — never overwrite an existing value. A stale MCP handle could otherwise clobber the user's curated identity. If a resolved value differs from what's already there, log a WARNING, skip the write, and surface the discrepancy at the end of the run.
If identity.md doesn't yet have a ## Profile section, create it using the template at the end of this skill and append after any existing top-of-file content. Never modify other sections (Preferences, Writing Style, Growth areas, etc.) — they are user-curated.
Determine date range and timezone: Use the argument if provided, otherwise default to today.
Timezone model:
identity.md's ## Profile section, field Timezone (IANA name, e.g., Asia/Dubai). Fall back to the system timezone if missing.Date conversion — the local-day window is [date 00:00:00, next_day 00:00:00) in the user's IANA TZ. Compute:
tz_offset from the IANA name (e.g., Asia/Dubai → +04:00, Europe/London → +01:00 BST or +00:00 GMT depending on date).local_start = {date}T00:00:00{tz_offset} and local_end = {next_day}T00:00:00{tz_offset}.utc_start = local_start.astimezone(UTC) and utc_end = local_end.astimezone(UTC).Worked example for date=2026-04-30, tz=Asia/Dubai:
local_start = 2026-04-30T00:00:00+04:00 → utc_start = 2026-04-29T20:00:00Zlocal_end = 2026-05-01T00:00:00+04:00 → utc_end = 2026-04-30T20:00:00ZPer-source query parameters:
after = utc_start, before = utc_end (Unix timestamps). Or use from:<@id> on:{date} query modifier; Slack interprets on: in the workspace TZ.gh search — pass full ISO timestamps with the offset, not bare dates: --created "{local_start}..{local_end}". Bare YYYY-MM-DD..YYYY-MM-DD interprets dates in UTC and shifts the window by the TZ offset, missing/misattributing PRs at day boundaries.{date} and {next_day} as YYYY-MM-DD strings with the half-open >= / < boundary (see Jira section). Caveat: Jira and Confluence evaluate JQL/CQL date literals in the user's profile timezone, not UTC — if the Jira profile TZ differs from the user's local TZ, results drift by hours. Recommend aligning the Jira profile TZ to the user's local TZ.viewedByMeTime and modifiedTime are RFC 3339 UTC; use utc_start / utc_end.Multi-day ranges: Loop internally over dates, executing steps 4–7 once per date. Produce one output file per date. One day's MCP responses fit in a single context window; multiple days may not.
Status semantics — apply consistently across the file's Status: header, the /log call, and any returned summary string:
## Gaps with the error reason, log status=WARNING. Do not abort.## Activity and the failure reason under ## Gaps. /log status is FAILED.Do not use PARTIAL to signal "the day isn't over yet" or "I expected more data". Coverage-time concerns belong in the ## Summary prose, not in the Status field.
Collect from sources in parallel:
Pagination — required for every source. Loop until exhausted; never trust the first page as the full result.
| Source | Mechanism |
|---|---|
| Slack | cursor — loop until no next cursor |
| Jira | startAt + maxResults — loop until isLast: true or returned count < maxResults |
| Confluence | Same as Jira via the Atlassian MCP |
GitHub (gh) | --limit 100 per query is effectively always enough for a single day; warn-if-hit rather than paginate further |
| Drive | pageToken — loop until no next page |
Stop-and-flag rule: this skill always operates at single-day, single-user granularity (multi-day args loop one day at a time). At that scope, if pagination hits 5+ pages on any single source — stop and flag. 500 events from one source on one day for one person is anomalous — almost always a wrong date boundary or a missing identity filter. Don't carry the assumption beyond this scope.
On partial failure: see Status semantics in step 3 — set Status=PARTIAL, /log status=WARNING, list the failed source under ## Gaps with its error reason, capture what's available, do not abort.
Slack:
detailed response format (never concise — it drops timestamps and permalinks). Set include_context: false to keep response size manageable; use slack_read_thread selectively for context.cursor parameter when results hit the page limitJira:
issueFunction in commented(...) is not portable across Jira instances; assignee/reporter/creator/updated paths cover the common cases).
(assignee = currentUser() OR reporter = currentUser()) AND updated >= "YYYY-MM-DD" AND updated < "next_day" — captures issues the user owns or reports that moved during the day.creator = "<accountId>" AND created >= "YYYY-MM-DD" AND created < "next_day" — captures new issues the user filed.>= "YYYY-MM-DD" AND < "next_day" (not <= — Jira treats <= "04-10" as "before start of 04-10").summary, status, issuetype, priority, updated, assignee, reporter.GitHub:
Use a script file Claude writes + executes; never gh auth switch. Top-level Bash with $(...) substitution is blocked by the sandbox guard, but $(...) inside a script file that Claude then runs via bash <script> is not — the guard inspects top-level commands, not script contents. Fetch the cached handle's token in-process: export GH_TOKEN="$(gh auth token --user <cached-handle>)". Token never enters tool output or transcripts; no global gh state mutation; no crash window.
Pre-flight (read-only): gh auth status to confirm the cached handle is logged in. If not, fail with a ## Gaps note suggesting gh auth login --hostname github.com. Never gh auth switch.
Date range syntax — pass full ISO timestamps with the user's TZ offset, not bare YYYY-MM-DD. Bare dates are interpreted as UTC, so non-UTC user TZs slip by the offset (Asia/Dubai --created "2026-04-30..2026-04-30" covers local 04-30 04:00 → 05-01 04:00, missing/misattributing PRs at day boundaries).
Four queries to run inside the script (after the GH_TOKEN export), with LOCAL_START and LOCAL_END set to the day's ISO timestamps:
gh search prs --author "@me" --created "${LOCAL_START}..${LOCAL_END}" --limit 100 --json number,title,url,repository,state,createdAt,updatedAtgh search prs --reviewed-by "@me" --updated "${LOCAL_START}..${LOCAL_END}" --limit 100 --json number,title,url,repository,stategh search issues --author "@me" --created "${LOCAL_START}..${LOCAL_END}" --limit 100 --json number,title,url,repository,stategh search issues --commenter "@me" --updated "${LOCAL_START}..${LOCAL_END}" --limit 100 --json number,title,url,repository--limit 100 defends against gh search's default --limit 30 silently truncating — the JSON output has no has_more flag, so a truncated result is indistinguishable from a complete one.
Range syntax A..B is inclusive on both ends — different from Jira's half-open convention above. Using next_day T00:00:00 as the upper bound therefore includes events at exactly midnight local; this is a 1-second overlap with the next day's window, acceptable for daily granularity.
With GH_TOKEN set to the cached handle's token, @me resolves to the business user regardless of the active gh handle.
For each result: capture the repo, number, title, and URL.
If gh is not available, note this gap and continue. If the token fetch errors (revoked grant, deleted handle), the script exits non-zero — surface the gh error in ## Gaps with the same re-auth hint as pre-flight failure.
Confluence:
searchConfluenceUsingCql: contributor = "{accountId}" AND lastmodified >= "YYYY-MM-DD" AND lastmodified < "next_day" (same date boundary logic as Jira)contributor field already covers comments — a comment is a Confluence contribution. No separate comment query needed.Google Drive:
The MCP's query language only supports title, fullText, mimeType, modifiedTime, viewedByMeTime as query terms. owners is not a supported field — neither 'email' in owners nor 'me' in owners works (both return "Unsupported query field"). Use a two-pronged approach instead:
Owned + edited by user — call mcp__claude_ai_Google_Drive__list_recent_files with orderBy: lastModifiedByMe, paginate on nextPageToken, post-filter results in code by the local-day window (createdTime/modifiedTime falling in [YYYY-MM-DDT00:00:00Z, NEXT_DAYT00:00:00Z)). This catches files the user authored or modified.
Touched (viewed/co-edited) by user — call mcp__claude_ai_Google_Drive__search_files with:
query: "viewedByMeTime >= 'YYYY-MM-DDT00:00:00Z'
and viewedByMeTime < 'NEXT_DAYT00:00:00Z'"
pageSize: 100
Paginate on pageToken. Use UTC bounds. Single quotes around values; escape inner singles as \'.
Deduplicate the union by id.
For each result: capture title, MIME type, action (created vs. modified, inferred from createdTime vs. modifiedTime), and the file URL.
Note on authorship inference: the search response doesn't reliably name the writer for non-owned files. For items only surfaced via query (2), the user touched the file but may not have edited it. Flag uncertain items in ## Gaps (e.g., "Drive items {ids} surfaced via viewedByMeTime — authorship not confirmed") rather than asserting they edited.
Oversized responses (50KB+): Write a targeted extraction script on the fly based on the actual response structure. Don't use pre-baked scripts — MCP schemas change.
Deduplicate and cross-reference: A single activity may appear in multiple sources (e.g., a Jira ticket discussed in Slack and linked in a PR). Group related items into a single entry with multiple source links rather than listing them separately.
Categorize each item into one or more of (categories are role-neutral — an IC, PM, EM, or director will naturally use different subsets):
engineering — Writing code, debugging, code reviews, technical problem-solvingarchitecture — Design decisions, technical direction, system design, RFCs, design docsteam — Mentoring, feedback, hiring, 1:1s, process improvements, onboardinginfrastructure — Infra, cost optimization, security, DevOps, incident responsedelivery — Sprint work, project tracking, unblocking dependencies, release managementproduct — Requirements, user research, feature specs, stakeholder alignment, roadmapoperational — Process improvements, monitoring, on-call, documentation, cross-team coordinationstrategic — Executive comms, OKRs, cross-org initiatives, vendor relationships, budgetai-engineering — AI tool adoption, AI-powered workflows, AI strategygrowth — Learning, conferences, training, certifications, knowledge sharingCapture a timestamp per item: For each activity item, record the earliest underlying event's timestamp as ISO 8601 with timezone offset (e.g., 2026-04-12T14:32:00+04:00). Use the user's timezone from <workspace>/me/identity.md. When an item spans multiple events (e.g., Slack thread + Jira update + PR), use the earliest. This enables downstream synthesis of time-based patterns (late-hour work, reactive windows, deferral over time).
Write the output file: Write to <workspace>/collected/collect-my-activity/YYYY-MM-DD-activity.md (using the user's local date). Create parent directories if missing.
Re-run on the same date: overwrite the file. Add a header line **Re-collection**: previous run superseded YYYY-MM-DD HH:MM:SS (UTC) below the title so the user can see this is a re-collection, not a fresh first run.
Gaps discipline: ## Gaps lists inaccessible sources only — sources that failed at runtime or were unavailable. A source returning zero results is not a gap; it's a successful query reflected in the absence of items under ## Activity. DMs are universally inaccessible via MCP — the user is asked about them at the end (step 9), they are not listed in ## Gaps. Typical valid Gap entries: gh CLI not available, Google Drive MCP not available, Confluence: timed out on page 2 — partial coverage, Drive items {ids} surfaced via viewedByMeTime — authorship not confirmed. Most files should have an empty Gaps section.
# My Activity: YYYY-MM-DD
## Status: SUCCESS
**Sources checked**: Slack, Jira, Confluence, GitHub (gh CLI / N/A), Google Drive (MCP / N/A)
## Summary
[1-2 sentences: what was the focus today. If a quiet day or PTO, say so.]
## Activity
### [category]
- **[brief description framed by impact, not just action]**
- Time: 2026-04-12T14:32:00+04:00
- Sources: [Slack permalink], [JIRA-123](url), [PR #45](url)
- Context: [why this matters — what decision was made, what was unblocked, what risk was mitigated]
### [category]
- ...
## Gaps
[Only pair-specific runtime issues. Empty if no source was inaccessible.]
Report to user:
Activity collected: YYYY-MM-DD
───────────────────────────────
Items found: [count]
Sources: Slack ([count]), Jira ([count]), Confluence ([count]), GitHub ([count or N/A]), Drive ([count or N/A])
Gaps: [list any inaccessible sources]
File: <workspace>/collected/collect-my-activity/YYYY-MM-DD-activity.md
Anything missing? Notable DMs, meetings, or whiteboard sessions to add?
/collect-team-activity. This skill only collects the user's own.zeebe-cluster-gateway-zeebe-0), use that name — do not substitute a related system (e.g., "Kafka") because they share vocabulary ("broker", "partition", "leader"). If the system name genuinely cannot be read from the source, write "system unclear" rather than guessing.identity.md from MCP — log a WARNING and surface the discrepancy instead.On completion (success or failure), invoke the /log skill:
/log run_id=<run_id> skill=collect-my-activity status=<SUCCESS|WARNING|FAILED> detail=<summary>
The run_id is passed by the calling agent (e.g., Chief of Staff). Use manual if invoked directly by the user.
<workspace>/me/identity.md formatThe skill reads structured fields from a single ## Profile section. Everything else in identity.md — Preferences, Writing Style, Growth areas, anything that surfaces during sessions — is human-curated and skills never touch it.
# Identity
## Profile
- **Name**: {full name}
- **Git user**: {git username}
- **Role**: {e.g., Software Engineer, Engineering Manager, Director}
- **Timezone**: {IANA TZ, e.g., Asia/Dubai}
- **Slack user ID**: {e.g., U01ABC123}
- **Atlassian account ID**: {e.g., 712020:abcdef-1234-...}
- **Jira cloud ID**: {UUID}
- **GitHub username**: {handle}
- **Google Workspace email**: {email}
## Preferences
{Free-form — user-curated}
## Writing Style
{Free-form — user-curated}
## Growth areas
{Free-form — maintained by /bye}
{any other sections that surface during sessions}
Skill contract:
## Profile. Layout above and below this section is the user's.## Profile when MCP resolves a field that isn't already there. Never overwrite an existing value.