Google Calendar
Changelog
Read Google Calendar CLI release notes, including new capabilities, changes and fixes.
Notable changes to @wirecat/gcal-cli. One section per version, newest first.
0.1.1 — 29.10.2026
Fixed
- The agent guide's header (
skills/gcal-cli/SKILL.md) is valid YAML again. ItsdescriptionheldCalendar: sync, which a YAML parser reads as a nested mapping, so strict skill loaders and the WireCat site's skills index refused the file. The text is unchanged apart from a dash in place of that colon.
0.1.0 — 29.10.2026
Added
gcal <profile> session start | status | endsigns in to Google in the browser, with read-only Calendar access. It uses your own Google OAuth client for now (--client-file, orGCAL_GOOGLE_CLIENT_IDandGCAL_GOOGLE_CLIENT_SECRET); settings says how to make one. The sign-in is kept in the system keyring, or with--credential-storage filein a private file (mode 600) where no keyring works.session status --checkasks Google whether the sign-in still works.--grant writealso asks forcalendar.events, which the event writes need, and--grant sharingforcalendar.acls, which sharing needs.gcal session listlists the profiles on this computer, each withsigned_in,accountandcredential_storage; no command ever picks a profile for you.gcal <profile> synccopies your calendars into the local WireCat store, and the read commands work offline.calendars list | sync | unsync,events list | show,search,people list | linkandlinks review | resolveare the WireCat shared calendar commands, so other WireCat tools see the same events and people. The first sync reads the calendars you own from a year back to three months ahead; each later one asks Google only for what changed. A repeating event's slots are stored one by one, cancelled slots included.sync --embedalso indexes events for search by meaning. Each answer names, underuntrusted, the fields an invitation's sender wrote, so an agent reads them as data.- A big sync goes on over several runs.
syncstops on its own before its time limit (15 minutes at a terminal, 45 seconds over MCP;--timeoutchanges it,--max-pages <n>lowers the requests to Google further) and saves after every page. A partial answer saysstate: "partial", how far it got, and the command to run next.--rescanstarts every calendar over.gcal <profile> statusshows each synced calendar's progress,partialorcomplete, and how long since it last moved. gcal <profile> calendars busyshows when calendars and people are taken, from Google's free/busy answer, which says when and never what.--duration-minuteslists the stretches free for all of them inside--hours(09:00-17:00 by default), Monday to Friday; whoever Google will not show is listed inunknown. Nothing is stored.gcal <profile> search --backend server <words>asks Google Calendar's own search over the synced calendars. It reads only, keeps nothing, and also finds events outside the synced span.--backend archive, the local store, is the default.gcal <profile> events create | update | delete | respondchange Google Calendar aftersession start --grant write. Without that grant a write fails withpermission_errorand names the flag. A change sends the synced version, so an event changed in Google since is anevent.conflict, never overwritten. A create whose answer was lost ends inoutcome_unknownwith an id; retried with that id, it finds the event.events create --repeat <rule>makes a repeating event, andevents update --series --repeat <rule>changes its rule. New dates on a timed event make it all-day, and new times make an all-day event timed, keeping its Meet link and Drive files.respondchanges only your own answer. The writes are MCP tools too, with the same options as the command line.gcal api list | show | call, and onegcal <profile> api <method>command per method, reach every Google Calendar API v3 method gcal can serve. They are generated from Google's description of the API, and each answer is checked against it. Google's change notifications (watch,channels.stop) are not offered: they need a public web address.- Every command and every Google Calendar method has a permission key, such as
events.createorapi.calendar.events.insert. A change asks first (--yesin a script), sharing a calendar and giving it to another account included; over MCP no one answers, soasklets an agent run it. Three keys aredenyuntil you allow them:events.notify(Google mails the attendees),events.delete.series(deleting every occurrence of a repeating event) andsharing.notify(Google mails the person a calendar is shared with). Theapicommands check the same keys as the event writes, and an event write also checks its Google method's key, sopermissions.api readonlystops both. Emptying a calendar (calendars.clear) is denied, and it is never offered over MCP, nor isapi call.--dry-runlists every key a call checks, with its level. A key that names no method is refused, andgcal doctorlists any saved in the file. - A meeting's passcode, PIN, access code and password never leave Google. They are never stored: a join link is
kept without its query string, and a line of an event's description or location that names a passcode, a password
or a PIN is dropped. The
apicommands remove them too, from every answer that holds an event, in the terminal and over MCP. gcal <profile> mcp serveserves the profile's commands to an agent, andmcp add claude-code | codex,mcp config,mcp check,mcp revokeandmcp server start | stop | statusset it up.--profiles <names|all>serves several profiles; no profile is ever picked, sogcal mcp servealone lists them and stops. The server tells the agent which text other people wrote, and control characters in an answer are shown visibly, so an invitation's text cannot hide anything from the agent.gcal --helpshows what gcal can do and where to start, andgcal guidegives step-by-step scenarios: setting up, giving an agent access, finding a time.gcal skill installadds the tool's skill for Claude Code, Codex, Gemini CLI, OpenClaw and Hermes Agent.gcal doctorshows what is set up, with no network and no keyring: the version, the paths, the store, the OAuth client, the profile lock and the sign-in files.gcal <profile> runs list | showshows the runs gcal kept, sign-in and sign-out included: successes for 7 days, failures for 30. Secrets are masked;config set record_input falsekeeps none of the words you type.