AgentSkillsCN

activity-timeline

为某位用户生成其 GitHub 或 GitLab 活动时间轴。自动生成包含提交记录、PR/MR、议题、发布、评审与星标数量的 Markdown 摘要。适用于用户希望了解自身活动轨迹、贡献历史,或想要快速概览自己曾参与的工作时使用。同时支持 GitHub(gh CLI)与 GitLab(glab CLI)。

SKILL.md
--- frontmatter
name: activity-timeline
description: Generate a timeline of GitHub or GitLab activity for a user. Creates a markdown summary of commits, PRs/MRs, issues, releases, reviews, and stars. Use when the user asks for their activity, contribution history, or wants a summary of what they worked on. Supports both GitHub (gh CLI) and GitLab (glab CLI).
compatibility: Requires gh CLI for GitHub or glab CLI for GitLab, authenticated
allowed-tools: Bash(gh:*) Bash(glab:*) Bash(prettier:*) Write Read
metadata:
  author: junkdog
  version: "1.4"

Activity Timeline Generator

Generate comprehensive timelines of GitHub or GitLab activity for a specified user and time period.

When to use this skill

  • User asks for their GitHub/GitLab activity or contribution history
  • User wants to see what they worked on in a given month
  • User asks for a summary of their recent work
  • User mentions "activity", "timeline", "contributions", or "what did I work on"

Arguments

Parse the user's request for:

  • Platform: GitHub or GitLab (infer from context, check CLAUDE.md, or ask)
  • Username: GitHub/GitLab username (check CLAUDE.md or ask if not specified)
  • Time period: Specific month (e.g., "January 2026") or "past 30 days" (default)
  • Output file: Where to save the timeline (default: ./timeline-YYYY-MM.md)

Execution steps

1. Determine parameters

code
Platform: GitHub (gh) or GitLab (glab) - infer or ask
Username: From CLAUDE.md, conversation context, or ask user
Period: Parse from request, default to past 30 days
Output: Parse from request or generate default filename

2. Calculate date range

For a specific month:

code
START_DATE=YYYY-MM-01
END_DATE=YYYY-MM-{last day of month}

For past 30 days:

code
START_DATE=$(date -d "30 days ago" +%Y-%m-%d)
END_DATE=$(date +%Y-%m-%d)

GitHub Instructions (gh CLI)

Fetch GitHub data

User events (recent activity feed)

Note: Events API only retains ~90 days of history. Filter by date range in jq.

bash
gh api users/{username}/events --paginate --jq '.[] | select(.created_at >= "{START_DATE}" and .created_at <= "{END_DATE}T23:59:59Z") | {type: .type, repo: .repo.name, created_at: .created_at, payload_action: .payload.action, ref: .payload.ref, ref_type: .payload.ref_type}'

PRs authored (using API for reliable date filtering)

bash
gh api "search/issues?q=author:{username}+type:pr+created:{START_DATE}..{END_DATE}" --jq '.items[] | {title: .title, repo: (.repository_url | split("/") | .[-1]), created_at: .created_at, state: .state, url: .html_url, number: .number}'

Issues created (using API for reliable date filtering)

bash
gh api "search/issues?q=author:{username}+type:issue+created:{START_DATE}..{END_DATE}" --jq '.items[] | {title: .title, repo: (.repository_url | split("/") | .[-1]), created_at: .created_at, state: .state, url: .html_url, number: .number}'

Releases from user's repos

bash
gh api users/{username}/repos --jq '.[].name' | while read repo; do
  gh api "repos/{username}/$repo/releases" --jq '.[] | select(.published_at >= "{START_DATE}") | {repo: "'$repo'", tag: .tag_name, published_at: .published_at, url: .html_url}' 2>/dev/null
done

Issues/PRs involving user (for external contributions)

bash
gh api "search/issues?q=involves:{username}+created:{START_DATE}..{END_DATE}+-author:{username}" --jq '.items[] | {title: .title, repo: (.repository_url | split("/") | .[-1]), created_at: .created_at, url: .html_url}'

Open PRs authored by user (all time, still active)

bash
gh api "search/issues?q=author:{username}+type:pr+state:open&per_page=100" --jq '.items[] | {title: .title, repo: (.repository_url | split("/") | .[-2:] | join("/")), created_at: .created_at, url: .html_url, number: .number, draft: .draft, labels: [.labels[].name]}'

Commits to specific repos (if needed for detail)

bash
gh api "repos/{owner}/{repo}/commits?since={START_DATE}&author={username}" --jq '.[] | {sha: .sha[0:7], date: .commit.author.date, message: (.commit.message | split("\n")[0])}'

Collect all repos with activity

Gather unique repos from user's account and from the events data. Note: Parse repos from the events you already fetched rather than re-fetching.

bash
# Get user's own repos
gh api users/{username}/repos --paginate --jq '.[].full_name'

# Also extract unique repos from the events API response (org repos where user contributes)
# Parse from the events data you fetched earlier, extracting unique .repo values

Star counts and changes for specific repos

For repos you want to track (user's repos + org repos they maintain), fetch individually:

bash
gh api "repos/{owner}/{repo}" --jq '{repo: .name, full_name: .full_name, stars: .stargazers_count, url: .html_url}'

Star events on a repo (who starred during period)

bash
gh api "repos/{owner}/{repo}/stargazers" -H "Accept: application/vnd.github.star+json" --paginate --jq '.[] | select(.starred_at >= "{START_DATE}" and .starred_at <= "{END_DATE}") | {user: .user.login, starred_at: .starred_at}' 2>/dev/null

To count stars gained in period:

bash
gh api "repos/{owner}/{repo}/stargazers" -H "Accept: application/vnd.github.star+json" --paginate --jq '.[] | select(.starred_at >= "{START_DATE}" and .starred_at <= "{END_DATE}")' 2>/dev/null | wc -l

Note: The stargazers endpoint with timestamps requires the star+json media type. This includes org repos where the user has activity (e.g., maintainer of ratatui/tachyonfx). To calculate net change, compare against previous period or track unstar events (which aren't directly available via API).


GitLab Instructions (glab CLI)

Fetch GitLab data

User's merge requests

bash
glab api "merge_requests?author_username={username}&created_after={START_DATE}T00:00:00Z&scope=all" --paginate | jq '.[] | {title: .title, project: .references.full, created_at: .created_at, state: .state, url: .web_url, iid: .iid, merged_at: .merged_at}'

User's issues

bash
glab api "issues?author_username={username}&created_after={START_DATE}T00:00:00Z&scope=all" --paginate | jq '.[] | {title: .title, project: .references.full, created_at: .created_at, state: .state, url: .web_url, iid: .iid}'

User's events/activity

bash
glab api "users/{username}/events?after={START_DATE}" --paginate | jq '.[] | {action: .action_name, target_type: .target_type, target_title: .target_title, created_at: .created_at, project: .project_id}'

Projects user contributed to

bash
glab api "users/{username}/contributed_projects" | jq '.[] | {name: .name, path: .path_with_namespace, url: .web_url}'

Commits in a specific project

bash
glab api "projects/{project_id}/repository/commits?author={username}&since={START_DATE}T00:00:00Z" | jq '.[] | {sha: .short_id, date: .created_at, message: (.title)}'

MR reviews/approvals

bash
glab api "merge_requests?reviewer_username={username}&created_after={START_DATE}T00:00:00Z&scope=all" --paginate | jq '.[] | {title: .title, project: .references.full, created_at: .created_at, url: .web_url}'

Releases (per project)

bash
glab api "projects/{project_id}/releases" | jq '.[] | select(.created_at >= "{START_DATE}") | {tag: .tag_name, name: .name, created_at: .created_at, url: ._links.self}'

Open MRs authored by user (all time, still active)

bash
glab api "merge_requests?author_username={username}&state=opened&scope=all" --paginate | jq '.[] | {title: .title, project: .references.full, created_at: .created_at, url: .web_url, iid: .iid, draft: .draft, labels: .labels, description: .description}'

Organize into timeline

Group events chronologically and categorize by:

  1. Releases - Version releases with links
  2. MRs/PRs merged - Merge/pull requests that were merged
  3. MRs/PRs opened - Merge/pull requests opened (note if still open)
  4. Issues - Issues created or closed
  5. Code reviews - Reviews on others' MRs/PRs
  6. Repos starred - Repos the user starred (GitHub only)
  7. Notable commits - Significant commits (features, fixes)
  8. Repository star changes - New stars gained on user's repos (GitHub only)
  9. Active PRs - All open PRs authored by the user (see below)

Generate summary statistics

For the summary section, calculate:

  • Number of releases per project
  • MRs/PRs authored (merged count)
  • External MRs/PRs reviewed
  • Issues created/closed
  • Repos starred by user (GitHub)
  • Stars gained on user's repositories (GitHub) - include per-repo breakdown if significant
  • Notable external contributors (if applicable)

Summarize active PRs

Fetch all open PRs authored by the user and create an intelligent summary:

  1. Group by repository - Organize PRs by the repository they target
  2. Categorize by type - Infer from title/labels: feature, bugfix, docs, refactor, dependency update
  3. Note age - Flag PRs that have been open for a long time (>2 weeks) as potentially stale
  4. Identify draft PRs - Mark draft PRs separately as work-in-progress
  5. Summarize intent - For each PR, write a brief 1-line summary based on title and body (if available)

When summarizing, look for patterns:

  • Multiple PRs in the same repo suggest active development focus
  • PRs across different orgs show breadth of contribution
  • Long-open PRs may need attention or follow-up
  • Draft PRs indicate ongoing work

For each active PR, include:

  • Repository name
  • PR number and title (linked)
  • Age (days since opened)
  • Status indicators: [draft], [stale], [waiting-review]
  • Brief context if discernible from title/body

Write output

Create markdown file with structure:

markdown
# {Platform} Activity Timeline: {Period Description}

## {Month/Period} {Year}

### {Date Range or Week}
- **{repo} {version} released** - {description}
- **{repo} MR/PR !/{#}{number} merged** - {title}
- ...

---

## {Period} Summary

| Metric | Count |
|--------|-------|
| **Releases** | X |
| **MRs/PRs merged** | X |
| **Stars gained** | +X |
| ...

### Repository Star Changes (GitHub)

| Repository | Stars | Change |
|------------|-------|--------|
| repo-name | 150 | +12 |
| other-repo | 45 | +3 |

### Notable External Contributors
- **{username}** - {contribution count/description}

---

## Active Pull Requests

Summary of all open PRs authored by {username} as of {current_date}.

### {repository_name}

| PR | Title | Age | Status |
|----|-------|-----|--------|
| [#{number}]({url}) | {title} | {X} days | {status_badges} |

**Context:** {brief summary of what these PRs are about, patterns noticed}

### {another_repository}
...

**Overall:** {X} open PRs across {Y} repositories. {Any observations about focus areas, stale PRs needing attention, etc.}

Format output

After writing the markdown file, format it with prettier to ensure tables are properly aligned:

bash
prettier --write {output_file}

This ensures markdown tables display correctly when viewed in the terminal.

Edge cases

  • No activity: Report "No activity found for this period"
  • Rate limiting: If API returns rate limit errors, wait and retry or inform user
  • Private repos/projects: Activity from private repos may not appear depending on permissions
  • Events API limit: GitHub Events API only retains ~90 days of history; for older periods, rely on commit/MR/issue searches instead
  • GitLab self-hosted: May need different API base URL; glab should handle this if configured

Platform detection tips

  • If user mentions "MR" or "merge request" -> GitLab
  • If user mentions "PR" or "pull request" -> GitHub
  • Check CLAUDE.md for configured usernames per platform
  • If unclear, ask: "Which platform - GitHub or GitLab?"