# Fetching Calendar Events for a Google Group's Shared Calendar with gogcli

> Easily fetch Google Group calendar events with gogcli. Aggregate and deduplicate events from all group members into one view. Learn how to use gog calendar team now!

- Repository: [Peter Steinberger/gogcli](https://github.com/steipete/gogcli)
- Tags: how-to-guide
- Published: 2026-02-16

---

**The `gog calendar team` command aggregates events from every member of a Google Group into a single deduplicated view using concurrent API calls and recursive group expansion.**

`gogcli` (available at `steipete/gogcli`) solves the visibility problem of Google Workspace shared calendars by providing a dedicated **team** sub-command. Rather than querying a single calendar ID, it resolves all members of a specified Google Group, fetches each person's calendar events in parallel, and merges the results into a unified output. This approach handles nested groups, eliminates duplicate meeting entries, and supports both detailed event data and lightweight free-busy queries.

## Understanding the Architecture

The implementation follows a layered pipeline that separates CLI parsing, group resolution, API communication, and output formatting.

- **CLI Entry Point**: The `calendar` command is registered in [`internal/cmd/calendar.go`](https://github.com/steipete/gogcli/blob/main/internal/cmd/calendar.go), which delegates to `CalendarTeamCmd.Run` defined in [`internal/cmd/calendar_team.go`](https://github.com/steipete/gogcli/blob/main/internal/cmd/calendar_team.go). This struct captures flags like `--group-email`, `--freebusy`, `--query`, and time-range options.

- **Group Resolution**: The `collectGroupMemberEmails` function in [`internal/cmd/groups.go`](https://github.com/steipete/gogcli/blob/main/internal/cmd/groups.go) walks the Google Group hierarchy via the Cloud Identity API. It handles nested groups and prevents infinite loops using a `seenGroups` tracker.

- **Service Initialization**: Factory functions in [`internal/googleapi/cloudidentity.go`](https://github.com/steipete/gogcli/blob/main/internal/googleapi/cloudidentity.go) and [`internal/googleapi/calendar.go`](https://github.com/steipete/gogcli/blob/main/internal/googleapi/calendar.go) create authenticated clients with the proper OAuth scopes required for directory reads and calendar access.

- **Time Handling**: Human-readable flags like `--today`, `--week`, or ISO timestamps are parsed by `ResolveTimeRange` and `ResolveTimeRangeWithDefaults` in [`internal/cmd/time_helpers.go`](https://github.com/steipete/gogcli/blob/main/internal/cmd/time_helpers.go), converting them to RFC 3339 timestamps in the target time zone.

## Resolving Group Members and Time Ranges

Before fetching any calendar data, the tool must expand the group into a flat list of user emails.

The `collectGroupMemberEmails` function recursively queries the Cloud Identity API to enumerate direct and nested members. It returns a sorted, deduplicated slice of email addresses while guarding against cyclic group memberships. Concurrently, the `ResolveTimeRange` function processes CLI arguments to establish precise start and end boundaries for the query window.

These preparatory steps ensure that subsequent API calls target the correct user set and time window without manual email list curation.

## Fetching and Deduplicating Events

The [`calendar_team.go`](https://github.com/steipete/gogcli/blob/main/calendar_team.go) file implements two distinct retrieval strategies controlled by the `--freebusy` flag.

**Free-Busy Mode**: When `--freebusy` is set, the `runFreeBusy` function issues a single batch request covering all group members. This returns availability windows without event titles or attendees, offering maximum performance for scheduling checks.

**Event Mode**: By default, `runEvents` spawns up to 10 concurrent goroutines (limited by a semaphore channel) to execute `Events.List` calls for each member. The implementation filters out declined invitations, private events (unless visible), and applies case-insensitive title matching via the `--query` flag.

After retrieval, the `dedupeTeamEvents` function merges events sharing the same `ICalUID` or `ID` + start time combination. Unless `--no-dedup` is specified, duplicate entries are consolidated into single rows with a combined "Who" column listing all attendees from the group.

## Practical Usage Examples

Fetch detailed events for the engineering group over the next two days, filtering for standups and outputting JSON:

```bash
gog calendar team engineering@mycompany.com \
    --from today \
    --days 2 \
    --query standup \
    --json

```

Retrieve a fast free-busy view for a custom time window without event details:

```bash
gog calendar team engineering@mycompany.com \
    --from 2026-03-01T09:00:00Z \
    --to   2026-03-01T17:00:00Z \
    --freebusy

```

Show raw events without deduplication to debug individual attendance patterns:

```bash
gog calendar team engineering@mycompany.com \
    --from week \
    --no-dedup

```

## Summary

- The `calendar team` command treats Google Groups as logical calendar collections rather than single calendar entities.
- Recursive group expansion in [`internal/cmd/groups.go`](https://github.com/steipete/gogcli/blob/main/internal/cmd/groups.go) handles complex organizational hierarchies and nested memberships.
- Concurrent fetching with a 10-worker semaphore maximizes throughput while respecting Google API rate limits.
- The deduplication engine in [`calendar_team.go`](https://github.com/steipete/gogcli/blob/main/calendar_team.go) uses deterministic keys (`ICalUID`) to merge shared meeting instances across multiple calendars.
- Both high-performance free-busy queries and full event detail retrieval are supported via the `--freebusy` flag.

## Frequently Asked Questions

### How does gogcli handle nested Google Groups?

The `collectGroupMemberEmails` function in [`internal/cmd/groups.go`](https://github.com/steipete/gogcli/blob/main/internal/cmd/groups.go) recursively traverses group memberships using the Cloud Identity API. It maintains a `seenGroups` map to detect and prevent infinite loops caused by circular group references, ensuring each member email appears only once in the final list.

### What is the difference between free-busy and event mode?

**Free-busy mode** (`--freebusy`) calls the `FreeBusy` API endpoint, which returns time slots marked as busy without revealing event titles, descriptions, or attendee lists. **Event mode** (default) calls `Events.List` for each member to retrieve full calendar details, subject to the viewer's sharing permissions, and supports title filtering via the `--query` parameter.

### Can I disable event deduplication when querying a group?

Yes. By default, `gogcli` merges events that share the same `ICalUID` to avoid showing the same meeting multiple times when several group members are invited. Adding the `--no-dedup` flag preserves each calendar's individual copy, which is useful for verifying per-person attendance or debugging sync issues.

### How does the tool manage API rate limits when querying large groups?

The `runEvents` function implements a concurrency semaphore (`sem := make(chan struct{}, 10)`) that limits simultaneous API requests to 10 goroutines. This prevents overwhelming the Google Calendar API while still parallelizing requests across group members for efficient data retrieval.