원클릭으로
collect-team-activity
Collect a team member's daily work activity from Slack, Jira, Confluence, and GitHub
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Collect a team member's daily work activity from Slack, Jira, Confluence, and GitHub
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 the user's daily work activity from Slack, Jira, Confluence, GitHub, and Google Drive with source links
Initialise a workspace, register projects under it, or sync upstream changes. Single entry point for workspace lifecycle.
| name | collect-team-activity |
| description | Collect a team member's daily work activity from Slack, Jira, Confluence, and GitHub |
| user_invocable | true |
| args | Pick a scope based on user intent — orchestrator builds the (member × date) pair list from these shapes: no args = all members today; '<name>' = specific member today; '<date>' = all members on that date; '<date range>' (e.g., '2026-04-07 to 2026-04-11') = all members across that range; '<name> <date>' or '<name> <date range>' = specific member, scoped date(s). Match member name loosely against team.md (first name, full name, case-insensitive). |
Collect work activity for one or all team members for one or more days from Slack, Jira, Confluence, and GitHub. Designed for engineering leadership (EM, director, VP). Multi-pair scopes fan out to sub-agents — one sub-agent per (member, day) pair — for context isolation and parallelism.
This skill reads from private Slack channels visible to the caller's Slack token (engineering, leadership, project channels) — not just public channels. Jira and Confluence access is bounded by the caller's Atlassian permissions; GitHub access uses the caller's gh identity (see "GitHub" section in the Executor Contract). Collected data lands on the caller's local disk under <workspace>/collected/collect-team-activity/. Intended for leadership oversight and 1:1 preparation with direct reports — do not run on members outside your direct report scope, and treat the output as confidential.
This skill has two roles:
/collect-team-activity.When scope resolves to exactly one (member, day) pair, the orchestrator runs the executor steps inline (no sub-agent spawn — overhead not worth it).
Setup — Resolve <workspace>: The skill's base directory is <workspace>/.claude/skills/collect-team-activity/; walk up three directory levels and validate that <workspace>/.claude/.workspace exists. Use this <workspace> for all path references below (identity, team, output). Abort with a setup-broken error if validation fails. Sub-agents (executors) inherit <workspace> from the orchestrator — they do not re-resolve.
Role guard: Read <workspace>/me/identity.md and check the user's title/role.
This skill is for leadership roles with direct reports.
Use /collect-my-activity for your own activity.
Pre-flight checks: Verify the environment before fanning out:
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 abort; (c) genuinely absent → abort (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 abort; (c) genuinely absent → abort (see below).gh CLI: Expected. 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. Sub-agents will record the same gap in their output files..claude/settings.json only — they cannot prompt for permissions. Verify the allowlist covers the MCP and CLI patterns sub-agents will call (Atlassian Rovo Jira/Confluence/Search, Slack search/read, gh search / gh auth status / gh auth token, plus bash /tmp/... for the script-file token pattern). Should already be in place from /collect-my-activity work.On required-tool failure, abort the run, surface a clear failure message to the user, and invoke /log with status=FAILED (see Logging section). No sentinel file — pre-flight failure means no pairs run, so there's no per-pair output to mark.
Resolve caller identity — MCP first, identity.md as cache, user input as last fallback:
General principle: probe the connected MCPs for any caller-derived value before reading identity.md, and only ask the user when both fail. identity.md is a cache, not a gate. The caller-identity fields the orchestrator needs are Timezone (fallback when a member has no TZ in team.md) and GitHub username (for the multi-account guard below).
atlassianUserInfo (caller).atlassianUserInfo.email; fallback: slack_read_user_profile.profile.email; ask the user only if both fail.gh supports multiple authenticated accounts. Team queries use --author <member-handle> so no @me substitution happens, but the active gh session must still be authenticated to an account with org access. 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."gh session. Sub-agents fetch the cached handle's token in-process via the script-file substitution pattern (see Executor Contract → GitHub). The cached handle name is the only thing the orchestrator passes through to sub-agents for the gh flow.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. Identity write-back is orchestrator-only; sub-agents must not touch identity.md.
Load team roster: Read <workspace>/me/team.md.
No team roster found at <workspace>/me/team.md
Create one with your direct reports and their platform IDs.
See the template at the bottom of this skill for the expected format.
Determine scope and build the (member, date) pair list: Parse the arguments.
/collect-team-activity Alice Chen 2026-04-10/collect-team-activity Alice Chen 2026-04-07 to 2026-04-11/collect-team-activity Alice Chen/collect-team-activity 2026-04-10/collect-team-activity 2026-04-07 to 2026-04-11/collect-team-activityMatch the member name loosely against the team roster (first name, full name, or case-insensitive). If no match, list available names and ask.
Cartesian-product the scoped members with the scoped dates → ordered list of (member, date) pairs. This list drives the fan-out.
Resolve per-member timezone:
Timezone (IANA name) from team.md if recorded.Timezone from identity.md's ## Profile.Time: fields with the right offset.Fan out:
Single (member, date) pair: skip the spawn. Run steps E1–E4 inline. Sub-agent overhead is not worth it for one pair.
Multi-pair: spawn one Agent (sub-agent_type=general-purpose) per pair. Batch by member, not by day. The Slack MCP rate-limits per session — concurrent sub-agents querying different members' Slack simultaneously trip this limit and return 0 results. Safe pattern: run all dates for one member in parallel (different date windows, same user = no contention), then wait for that member to complete before starting the next member. Never include more than one member in the same parallel batch. Each member's dates emit as one Agent tool-call message (up to 5 dates in parallel), then wait before starting the next member.
Sub-agent prompt template — fill in for each pair:
You are an executor sub-agent for /collect-team-activity. Your job is steps
E1–E4 of the collect-team-activity SKILL.md for exactly one (member, date)
pair. Do not deviate from the executor contract.
Inputs:
- Member name: {member_name}
- Member slug: {member_slug}
- Member Slack ID: {slack_id}
- Member Jira ID: {jira_account_id}
- Member GitHub: {github_handle}
- Member timezone: {iana_tz}
- Jira cloud ID: {jira_cloud_id}
- Date (local): {YYYY-MM-DD}
- Output file path: <workspace>/collected/collect-team-activity/{member_slug}/{YYYY-MM-DD}-{member_slug}-activity.md
- Run ID: {run_id}
Read .claude/skills/collect-team-activity/SKILL.md and follow the
"Executor Contract" section. Do not run the orchestrator steps.
Write the output file. Call /log with status SUCCESS, PARTIAL, or
FAILED. Return a one-line summary in the form:
{SUCCESS|PARTIAL|FAILED} {member_slug} {YYYY-MM-DD}: {n} items, gaps: {list or "none"}
Do not return MCP raw responses to the orchestrator — the output file
is the durable artefact.
Permission inheritance reminder: sub-agents inherit .claude/settings.json only. They cannot prompt for permissions. If a sub-agent fails with a permission error, the allowlist needs updating — do not retry as-is.
Aggregate:
Status: header (SUCCESS / PARTIAL / FAILED) and the ## Activity count./log entry summarising the run.This section describes the steps a sub-agent (or the orchestrator inline, in single-pair mode) follows for one (member, date) pair. Inputs: member name + slug, member Slack ID, member Jira account ID, member GitHub handle, member IANA timezone, Jira cloud ID (per-Atlassian-instance — sourced from identity.md's ## Profile, not from team.md, since it identifies the org's Atlassian instance and is shared across all members), single date (YYYY-MM-DD), pre-computed output file path, run ID.
Status semantics (apply consistently across the file's Status: header, the /log call, and the returned summary string):
## Activity and the failed source under ## Gaps with the error reason. /log status is WARNING.## 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 than I found". Coverage-time concerns belong in the ## Summary prose, not in the Status field.
E1. Collect from sources in parallel (single member, single day):
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 |
Stop-and-flag rule: at single-day, single-member granularity, if pagination hits 5+ pages on any single source — stop and flag in ## Gaps. 500 events from one source on one day for one person is anomalous — almost always a wrong date boundary or a wrong identity filter.
On partial failure: see Status semantics above — set Status=PARTIAL, /log status=WARNING, list the failed source under ## Gaps with its error reason, capture what's available, do not abort.
Date boundary handling (consistent across sources):
The local-day window is [date 00:00:00, next_day 00:00:00) in the member'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 which is usually fine for GCC teams.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 member's Jira profile TZ differs from the executor's resolved TZ, results drift by hours.Slack:
slack_search_public_and_private for messages from the member using {slack_id}. This surfaces all channels the caller has access to, including private leadership/engineering channels that are legitimately relevant to team activity collection.detailed response format (never concise — it drops timestamps and permalinks). Set include_context: false to keep response size manageable.?thread_ts=<parent_ts>&cid=<channel_id> — preserve this exactly; never reconstruct Slack URLs).cursor.Reply count > 0 AND the message is question- or decision-shaped (contains "?", directly @-mentions someone with a request, or uses "can we / should we / please / could you"). For each such message (cap at 5 per day), call slack_read_thread and capture the last substantive non-bot reply as a Thread outcome: line on the activity item. This surfaces whether a request was actioned, a decision was made, or the question is still open — without reading all threads indiscriminately.Jira: Two queries:
(assignee = "{jira_account_id}" OR reporter = "{jira_account_id}") AND updated >= "YYYY-MM-DD" AND updated < "next_day"creator = "{jira_account_id}" AND created >= "YYYY-MM-DD" AND created < "next_day">= "YYYY-MM-DD" AND < "next_day".summary, status, issuetype, priority, updated, assignee, reporter.Classify each returned ticket before capturing:
Reporter-only (member is reporter, not assignee): light capture only — key, title, assignee name, current status. No description or context block. Label as "Filed by {member}; assigned to {assignee-name}." These are planning/oversight signals, not delivery signals. Group separately in the output under "Filed (reporter-only)".
Assignee (member is assignee, with or without also being reporter): full detail. Then check for execution evidence:
execution: status-change. Strong delivery signal.updated in the window → fetch this ticket via getJiraIssue and check whether the member's {jira_account_id} appears in any comment within the window. If yes → flag execution: commented. If no → flag execution: none (awareness/planning — ticket is in queue, not acted on).getJiraIssue calls at 5 per executor. If more than 5 assignee tickets have status unchanged, prioritise the most recently updated ones.Both (member is assignee and reporter): treat as assignee for detail and execution evidence.
Output: group tickets as "Owned (assignee)" and "Filed (reporter-only)" so downstream synthesis can apply role-appropriate interpretation.
Confluence:
searchConfluenceUsingCql: contributor = "{jira_account_id}" AND lastmodified >= "YYYY-MM-DD" AND lastmodified < "next_day".contributor field already covers comments — a comment is a Confluence contribution. No separate comment query needed.GitHub: Use the script-file token pattern (same as /collect-my-activity). The sub-agent writes a script containing export GH_TOKEN="$(gh auth token --user <cached-handle>)" followed by the four gh search queries, then runs it via bash <script>. The $(...) substitution inside the script file is not blocked by the sandbox guard (which only inspects top-level Bash commands). Token lives in the bash subshell only — never appears in tool output. Never call gh auth switch.
Pre-flight (read-only): confirm the cached handle is logged in via gh auth status. If absent, fail with PARTIAL and record the gap with a re-auth hint (gh auth login --hostname github.com).
Use full ISO timestamps with the member's TZ offset, not bare YYYY-MM-DD. Bare dates are interpreted as UTC, so for non-UTC member TZs the window slips by the offset (e.g., for Asia/Dubai, --created "2026-04-30..2026-04-30" covers UTC 04-30 = local 04-30 04:00 → 05-01 04:00, missing 4 hours of local 04-30 and including 4 hours of local 05-01).
Four queries to run inside the script (after the GH_TOKEN export), with {github_handle} = the member's GitHub username and LOCAL_START/LOCAL_END set to the day's ISO timestamps:
gh search prs --author {github_handle} --created "${LOCAL_START}..${LOCAL_END}" --limit 100 --json number,title,url,repository,state,createdAt,updatedAtgh search prs --reviewed-by {github_handle} --updated "${LOCAL_START}..${LOCAL_END}" --limit 100 --json number,title,url,repository,stategh search issues --author {github_handle} --created "${LOCAL_START}..${LOCAL_END}" --limit 100 --json number,title,url,repository,stategh search issues --commenter {github_handle} --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.
A..B is inclusive on both ends — different from Jira's half-open convention. 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.gh is not available, note this gap and continue.Google Drive: Permanently out of scope for this skill. The Drive MCP's only date filters (viewedByMeTime, list_recent_files orderBy: lastModifiedByMe) are caller-perspective — they cannot surface another user's activity. The owners query field is unsupported. Without admin / Drive Audit access, the Drive MCP cannot answer "what did this team member do". This is a permanent property of the skill, not a per-pair gap — do not list it in the per-file ## Gaps section (see "Gaps discipline" under E3). The aggregate report mentions it once if relevant.
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.
E2. 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), using the resolved member TZ. When an item spans multiple events, use the earliest.
E3. Write the output file to the pre-computed path. Create parent directories if missing.
Re-run on the same (member, date): overwrite the file. Add a header line **Re-collection**: previous run superseded YYYY-MM-DD HH:MM:SS (UTC) below the title.
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. Permanent skill-level out-of-scope sources (Drive, DMs) are documented in this SKILL and the orchestrator's aggregate report — do not repeat them in per-file ## Gaps. Typical valid Gap entries: gh CLI not available, Confluence: timed out on page 2 — partial coverage, Slack permission denied. Most files should have an empty Gaps section.
# {Member Name} Activity: YYYY-MM-DD
## Status: SUCCESS
**Sources checked**: Slack, Jira, Confluence, GitHub (gh CLI / N/A)
## Summary
[1-2 sentences: what was the focus that day. 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.]
E4. Log and return:
/log run_id={run_id} skill=collect-team-activity status=<SUCCESS|WARNING|FAILED> detail={member-slug} YYYY-MM-DD: {summary}
If running as a sub-agent, return a one-line summary string in the form:
{SUCCESS|PARTIAL|FAILED} {member-slug} {YYYY-MM-DD}: {n} items, gaps: {list or "none"}
If running inline (orchestrator single-pair path), no return is needed — the orchestrator continues to step 8 with knowledge of the file path.
After aggregation:
Single (member, date) pair:
Team activity collected: {Member Name} (YYYY-MM-DD)
─────────────────────────────────────────────────────
Items found: {count}
Sources: Slack ({count}), Jira ({count}), Confluence ({count}), GitHub ({count or N/A})
Gaps: {list any inaccessible sources}
File: <workspace>/collected/collect-team-activity/{member-slug}/YYYY-MM-DD-{member-slug}-activity.md
Multi-pair:
Team activity collected: {first-date} to {last-date}
──────────────────────────────────────────────────
Members × days: {n}/{total} succeeded ({n_partial} partial, {n_failed} failed)
Total items: {sum across all SUCCESS/PARTIAL files}
Failed pairs: {list or "none"}
Files: <workspace>/collected/collect-team-activity/<member-slug>/...
The orchestrator emits a single summary log entry on completion:
/log run_id=<run_id> skill=collect-team-activity status=<SUCCESS|WARNING|FAILED> detail=<scope-summary>: <n_pairs> pairs, <n_succeeded> succeeded
Each executor sub-agent emits its own per-pair log entry (E4 above). Use manual as run_id if the orchestrator was invoked directly by the user; otherwise pass through the calling agent's run_id.
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.slack_search_public_and_private because leadership-relevant decisions surface in private channels. Access is bounded by what the caller's Slack token can see./collect-my-activity. This skill collects other people's activity. For the user's own activity, use /collect-my-activity.identity.md. The orchestrator never overwrites an existing value — log a WARNING and surface the discrepancy instead.gh accounts. Use the script-file token-fetch pattern: each sub-agent writes a script that does export GH_TOKEN="$(gh auth token --user <cached-handle>)" and runs its gh queries inside that script. Never gh auth switch. Token lives in the bash subshell only — never in tool output or the conversation transcript.The skill expects <workspace>/me/team.md to follow this structure:
# My Team
## Direct Reports
### Alice Chen
- **Role**: Backend Engineer
- **Timezone**: Asia/Dubai
- **Slack**: U01ABC123
- **Jira**: 712020:abcdef-1234-5678-abcd-1234567890ab
- **GitHub**: alicechen
### Bob Smith
- **Role**: Frontend Engineer
- **Timezone**: Europe/London
- **Slack**: U02DEF456
- **Jira**: 712020:fedcba-4321-8765-dcba-0987654321ba
- **GitHub**: bobsmith
Platform IDs can be resolved by:
slack_search_users by name, or check a user's profile in the Slack UIlookupJiraAccountId by email, or check in Jira adminAsia/Dubai); skill falls back to the caller's TZ if absent