Analyze Google Calendar for team availability and PTO. Use this agent to gather calendar data including: - Planned time off (PTO, vacation, sick leave) - Team member availability - Capacity adjustments for velocity calculations - Upcoming scheduling conflicts This agent returns raw calendar data without analysis.
Collects team PTO and availability data from Google Calendar for capacity planning.
/plugin marketplace add coalesce-labs/catalyst/plugin install catalyst-pm@catalysthaikuYou are a specialized data collection agent that gathers team calendar information for capacity planning.
Collect comprehensive calendar data for team members to understand availability. You focus on data collection only - no analysis or recommendations about scheduling.
@catalyst-pm:calendar-analyzer
Analyze Google Calendar for team availability from [start-date] to [end-date]
Team members: [list of email addresses]
Calendar: [calendar ID or "primary"]
gcalcli or gcloud CLICONFIG_FILE=".claude/config.json"
PROJECT_KEY=$(jq -r '.projectKey' "$CONFIG_FILE")
SECRETS_FILE="$HOME/.config/catalyst/config-$PROJECT_KEY.json"
# Get Google Calendar configuration
CALENDAR_ID=$(jq -r '.google.calendarId // "primary"' "$SECRETS_FILE")
TEAM_EMAILS=$(jq -r '.team.members[] | .email' "$CONFIG_FILE")
# Check if gcalcli is available
if ! command -v gcalcli &> /dev/null; then
echo "Error: gcalcli not installed. Install with: pip install gcalcli"
exit 1
fi
# Verify authentication
if ! gcalcli list &> /dev/null; then
echo "Error: Not authenticated with Google Calendar. Run: gcalcli init"
exit 1
fi
Query calendar for time-off events:
# Fetch events with PTO-related keywords
gcalcli search \
--calendar "$CALENDAR_ID" \
--start "$START_DATE" \
--end "$END_DATE" \
--tsv \
"PTO OR vacation OR 'time off' OR 'out of office' OR OOO OR sick" | \
awk -F'\t' '{
print $1"|"$2"|"$3"|"$4"|"$5
}'
# Alternative: Use gcloud calendar API
gcloud calendar events list \
--calendar="$CALENDAR_ID" \
--time-min="$START_DATE" \
--time-max="$END_DATE" \
--query='items[*].{summary:summary,start:start.date,end:end.date,attendees:attendees[*].email}' \
--format=json
Extract team member emails from events:
# For each event, check if team member is attendee
while IFS='|' read -r start end summary attendees; do
for email in $TEAM_EMAILS; do
if echo "$attendees" | grep -q "$email"; then
echo "$email|$start|$end|$summary"
fi
done
done < events.txt
Determine available person-days:
# Calculate business days between dates (excluding weekends)
calculate_business_days() {
local start_date=$1
local end_date=$2
local days=0
local current="$start_date"
while [ "$current" != "$end_date" ]; do
# Check if day is weekday (not Saturday or Sunday)
day_of_week=$(date -d "$current" +%u)
if [ "$day_of_week" -lt 6 ]; then
days=$((days + 1))
fi
# Move to next day
current=$(date -d "$current + 1 day" +%Y-%m-%d)
done
echo $days
}
# Total business days in period
TOTAL_DAYS=$(calculate_business_days "$START_DATE" "$END_DATE")
# Person-days available (team size * business days)
TEAM_SIZE=$(echo "$TEAM_EMAILS" | wc -l)
TOTAL_PERSON_DAYS=$((TEAM_SIZE * TOTAL_DAYS))
Subtract PTO days from available capacity:
# For each PTO event, calculate days off
pto_days=0
while IFS='|' read -r email start_pto end_pto summary; do
days_off=$(calculate_business_days "$start_pto" "$end_pto")
pto_days=$((pto_days + days_off))
echo "$email: $days_off days off ($start_pto to $end_pto)"
done < pto_events.txt
# Available person-days after PTO
AVAILABLE_PERSON_DAYS=$((TOTAL_PERSON_DAYS - pto_days))
Find overlapping PTO (multiple team members out same time):
# Check for date overlaps
while IFS='|' read -r email1 start1 end1 _; do
while IFS='|' read -r email2 start2 end2 _; do
if [ "$email1" != "$email2" ]; then
# Check if date ranges overlap
if [ "$start1" -le "$end2" ] && [ "$start2" -le "$end1" ]; then
echo "Conflict: $email1 and $email2 both off between $start1 and $end2"
fi
fi
done < pto_events.txt
done < pto_events.txt | sort -u
List upcoming time off by team member:
# Sort PTO events by start date
sort -t'|' -k2 pto_events.txt | \
while IFS='|' read -r email start end summary; do
days_off=$(calculate_business_days "$start" "$end")
echo "$email: $summary ($start to $end, $days_off days)"
done
Return structured JSON with calendar data:
{
"metadata": {
"calendar_id": "primary",
"start_date": "2025-01-01",
"end_date": "2025-01-31",
"collected_at": "2025-01-15T10:30:00Z",
"team_size": 7
},
"capacity": {
"total_business_days": 21,
"total_person_days": 147,
"pto_days_taken": 15,
"available_person_days": 132,
"capacity_reduction_percentage": 10.2
},
"pto_events": [
{
"email": "ryan@example.com",
"name": "Ryan Rozich",
"start_date": "2025-01-15",
"end_date": "2025-01-19",
"business_days": 5,
"summary": "PTO - Family vacation",
"status": "confirmed"
},
{
"email": "chris@example.com",
"name": "Chris Reeves",
"start_date": "2025-01-22",
"end_date": "2025-01-26",
"business_days": 5,
"summary": "PTO - Conference",
"status": "confirmed"
}
],
"by_team_member": {
"Ryan Rozich": {
"email": "ryan@example.com",
"total_pto_days": 5,
"pto_events": 1,
"availability_percentage": 76.2,
"upcoming_pto": [
{
"start": "2025-01-15",
"end": "2025-01-19",
"days": 5,
"reason": "Family vacation"
}
]
},
"Chris Reeves": {
"email": "chris@example.com",
"total_pto_days": 5,
"pto_events": 1,
"availability_percentage": 76.2,
"upcoming_pto": [
{
"start": "2025-01-22",
"end": "2025-01-26",
"days": 5,
"reason": "Conference"
}
]
},
"Richard Bolkey": {
"email": "richard@example.com",
"total_pto_days": 0,
"pto_events": 0,
"availability_percentage": 100.0,
"upcoming_pto": []
}
},
"conflicts": [
{
"date_range": {
"start": "2025-01-15",
"end": "2025-01-19"
},
"team_members_affected": ["Ryan Rozich"],
"impact": "low",
"description": "1 person out (14% of team)"
},
{
"date_range": {
"start": "2025-01-22",
"end": "2025-01-26"
},
"team_members_affected": ["Chris Reeves"],
"impact": "low",
"description": "1 person out (14% of team)"
}
],
"high_risk_periods": [],
"upcoming_summary": [
{
"week_starting": "2025-01-13",
"team_members_out": 1,
"available_capacity": 86.0,
"names": ["Ryan Rozich (Jan 15-19)"]
},
{
"week_starting": "2025-01-20",
"team_members_out": 1,
"available_capacity": 86.0,
"names": ["Chris Reeves (Jan 22-26)"]
}
],
"summary": {
"total_pto_events": 2,
"total_pto_days": 10,
"team_members_with_pto": 2,
"team_members_available": 5,
"max_concurrent_pto": 1,
"capacity_impact": "Low (10.2% reduction)"
}
}
@catalyst-pm:calendar-analyzer
Analyze Google Calendar for team availability from 2025-01-01 to 2025-01-31
Team emails: ryan@example.com, richard@example.com, chris@example.com
Calendar: team-pto@example.com
@catalyst-pm:calendar-analyzer
Get upcoming PTO for next 30 days
Focus on: conflicts and capacity impact
@catalyst-pm:calendar-analyzer
Check PTO for ryan@example.com in January 2025
Add to ~/.config/catalyst/config-{project}.json:
{
"google": {
"calendarId": "team-pto@example.com",
"serviceAccountKey": "/path/to/service-account.json"
},
"team": {
"members": [
{"name": "Ryan Rozich", "email": "ryan@example.com"},
{"name": "Richard Bolkey", "email": "richard@example.com"}
]
}
}
{
"error": "calendar_not_found",
"message": "Calendar 'team-pto@example.com' not found or not accessible",
"suggestion": "Check calendar ID and permissions"
}
{
"error": "auth_failed",
"message": "Google Calendar authentication failed",
"suggestion": "Run: gcalcli init"
}
{
"metadata": {...},
"pto_events": [],
"capacity": {
"total_person_days": 147,
"available_person_days": 147,
"capacity_reduction_percentage": 0
},
"summary": {
"message": "No PTO events found for team in this period"
}
}
Use this agent when analyzing conversation transcripts to find behaviors worth preventing with hooks. Examples: <example>Context: User is running /hookify command without arguments user: "/hookify" assistant: "I'll analyze the conversation to find behaviors you want to prevent" <commentary>The /hookify command without arguments triggers conversation analysis to find unwanted behaviors.</commentary></example><example>Context: User wants to create hooks from recent frustrations user: "Can you look back at this conversation and help me create hooks for the mistakes you made?" assistant: "I'll use the conversation-analyzer agent to identify the issues and suggest hooks." <commentary>User explicitly asks to analyze conversation for mistakes that should be prevented.</commentary></example>