Calendar sync via gcalcli
Converts GitHub/Linear activity data into calendar events using gcalcli. Claude uses this when you request to sync development work to Google Calendar from markdown reports, JSON files, or structured activity data.
/plugin marketplace add jongwony/cc-plugin/plugin install google@cc-pluginThis skill inherits all available tools. When active, it can use any tool Claude has access to.
references/duration-guide.mdreferences/gcalcli-reference.mdConvert structured activity data from GitHub, Linear, and other sources into executable gcalcli commands for Google Calendar import.
Use AskUserQuestion to gather required information interactively:
Calendar selection:
# List available calendars
calendars=$(gcalcli list)
Prompt user with AskUserQuestion:
gcalcli list output (primary calendar, work calendar, etc.)Timezone detection (optional):
# Auto-detect system timezone
TZ_ABBR=$(date +%Z) # e.g., "KST", "PST"
If user request specifies different timezone or auto-detection fails, use AskUserQuestion to confirm.
Duplicate check preference:
Accept input in three formats:
Markdown table (from github-activity skill):
| Time | Activity |
|-------|----------|
| 09:00 | 🔨 **Commits**: 3 commits in `org/repo` |
| 17:00 | 🔀 **PR Created**: [#234](url) "title" in `org/repo` |
JSON file (GitHub/Linear activity output):
{
"activities": [
{
"type": "commit|pr_created|pr_merged|issue_comment|...",
"timestamp": "2025-11-01T10:30:00Z",
"title": "PR #234: Add user auth",
"url": "https://github.com/org/repo/pull/234"
}
]
}
Structured data: Direct activity objects from other skills.
Extract from markdown using regex:
\d{2}:\d{2}🔨|🔀|✅|🔍|💬|🆕[#\d+](url)Convert timestamps to local timezone using config.
Key insight: Activity timestamps represent completion time, not start time.
Backdate calculation: start_time = timestamp - duration
| Activity Type | Duration | Example: timestamp 09:00 |
|---|---|---|
| Commits | 30 min | → 08:30-09:00 |
| PR Created | 60 min | → 08:00-09:00 |
| PR Review | 45 min | → 08:15-09:00 |
| Issue Comment | 15 min | → 08:45-09:00 |
For detailed duration rules: references/duration-guide.md
Time snapping (15-minute grid for calendar readability):
08:37 start → snap to 08:30
08:52 start → snap to 08:45
Group related activities into coherent work sessions for clean calendar visualization.
Session formation rules:
Example transformation:
Raw activity data:
09:00 🔨 Commit A (30min work)
09:30 🔨 Commit B (30min work)
10:00 🔀 PR #234 created (60min work)
Before (forward projection - wrong):
09:00-09:30 🔨 Commit A
09:30-10:00 🔨 Commit B
10:00-11:00 🔀 PR #234 ← extends into future!
After (backdate + session merge - correct):
08:30-10:00 🔨🔀 Work session: 2 commits + PR #234 in org/repo
Overlap resolution (when backdated blocks collide):
Input:
09:00 🔨 Commit (30min) → 08:30-09:00
09:15 💬 Comment (15min) → 09:00-09:15
Resolution: Merge into 08:30-09:15 session
Session output format:
{icons} {summary} in {repo}Work session timeline:
08:30 → 🔨 Started coding
09:00 → 🔨 Commit A pushed
09:30 → 🔨 Commit B pushed
10:00 → 🔀 PR #234 created
https://github.com/org/repo/pull/234
User override: "without grouping" or "separate events" to disable session merge.
Query existing events using gcalcli:
gcalcli --calendar "email" agenda "start_time" "end_time"
Compare by:
Prompt user for duplicate handling: y (add anyway), n (skip), s (skip all duplicates).
Default: Duplicate check enabled. Disable with explicit user request: "without duplicate check".
Output executable bash script with backdated sessions:
#!/bin/bash
set +e # Continue on error
SUCCESS=0
FAILED=0
FAILED_COMMANDS=()
# Session: backdated from 09:30 (last commit) by 30min
echo -n "[1] 2025-11-01 09:00-09:30 🔨 Work session... "
if gcalcli add --calendar "email" \
--title "🔨 3 commits in org/repo" \
--when "2025-11-01 09:00" \
--duration 30 \
--description "Session: 09:00-09:30
09:10 → Commit: Setup auth
09:20 → Commit: Add tests
09:30 → Commit: Update docs
https://github.com/org/repo" \
--where "GitHub" > /dev/null 2>&1; then
echo "✓"
((SUCCESS++))
else
echo "✗"
((FAILED++))
FAILED_COMMANDS+=("gcalcli add ...")
fi
# Summary
echo "Import Summary: $SUCCESS/$TOTAL succeeded"
[ $FAILED -gt 0 ] && {
printf '%s\n' "${FAILED_COMMANDS[@]}" > "$FAILED_LOG"
echo "Failed commands: $FAILED_LOG"
exit 1
}
Log location: ~/.claude/tmp/calendar-sync/logs/failed_imports_YYYYMMDD_HHMMSS.log
| Type | Icon | Title Prefix | Duration | Where |
|---|---|---|---|---|
| commit | 🔨 | "Commits" | 30 min | GitHub |
| pr_created | 🔀 | "PR Created" | 60 min | GitHub |
| pr_merged | ✅ | "PR Merged" | 15 min | GitHub |
| pr_review | 🔍 | "PR Review" | 45 min | GitHub |
| issue_comment | 💬 | "Issue Comment" | 15 min | GitHub |
| issue_created | 🆕 | "Issue Created" | 30 min | GitHub |
| linear_issue_created | 🎫 | "Linear Issue" | 30 min | Linear |
| linear_status_change | 🔄 | "Status Change" | 15 min | Linear |
Error: gcalcli list returns empty or fails.
Solution:
gcalcli --help to trigger OAuth authenticationError: gcalcli OAuth token expired.
Solution: Run gcalcli --help to trigger OAuth re-authentication flow. Follow browser prompts to grant access.
Error: gcalcli rejects timestamp.
Solution: Ensure timestamps are YYYY-MM-DD HH:MM format. Check timezone conversion is applied correctly from config.
Cause: Events already exist in calendar for specified time range.
Solution:
gcalcli agenda start_date end_dateCause: Some gcalcli commands failed during batch import.
Solution: Check failed command log at ~/.claude/tmp/calendar-sync/logs/failed_imports_*.log. Resolve issues (auth, format, network) and run log file as bash script to retry.
This skill should be used when the user asks to "create a hookify rule", "write a hook rule", "configure hookify", "add a hookify rule", or needs guidance on hookify rule syntax and patterns.
Create distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.