@ipulsehq/pulsecalendar-cli
v0.5.0
Published
Command line interface for PulseCalendar: log in once on your device, read your agenda (events from all your calendars), find free time, create/move/delete events, and manage work tasks.
Readme
@ipulsehq/pulsecalendar-cli
Command line interface for PulseCalendar. Log in once on your device with a browser, then read your agenda, find free time, create/move/delete events and manage work tasks from your terminal (or from tools like Claude Code).
Built for AI assistants: every read command supports --json, accepts relative
dates ("today", "tomorrow", "+3d", "tomorrow 09:00"), and the agenda expands
recurring events into concrete occurrences so an agent can answer "what's on my
calendar?" without understanding RRULEs.
It also respects your PulseCalendar settings: new events land on your default
calendar and use your default duration, free uses your configured working
hours, weekend visibility and week start. Override any of these with flags.
Install
npm install -g @ipulsehq/pulsecalendar-cliThis installs two equivalent binaries: pulsecalendar and the short alias
pulsecal.
Log in
pulsecalendar loginThis opens your browser, signs you in through iPulse (OAuth with loopback
PKCE, same flow as the PulseEnv CLI), and stores tokens in
~/.pulsecalendar/credentials.json. Only iPulse admin accounts can use the
CLI (PulseCalendar is an internal tool), and your account must have signed in
to the PulseCalendar web app at least once.
Access tokens are short-lived and refreshed automatically via the stored refresh token; you only need to log in again when the refresh token expires (30 days of inactivity).
To point at a non-production instance:
pulsecalendar login --url http://localhost:3000
# or set it for the whole session:
export PULSECALENDAR_URL=http://localhost:3000
# the OAuth issuer can be overridden too:
export PULSECALENDAR_ISSUER=https://ipulse.oneRead your agenda
pulsecalendar agenda # today
pulsecalendar agenda --tomorrow
pulsecalendar agenda --week # current week (Mon-Sun)
pulsecalendar agenda --month
pulsecalendar agenda --days 7 # next 7 days
pulsecalendar agenda --from 2026-07-01 --to 2026-07-07
pulsecalendar agenda --calendar <id> # one calendar only
pulsecalendar agenda --week --json # full details for an AI assistantCalendars you've turned off (hidden) in PulseCalendar are excluded, just like in
the web app. Pass --include-hidden to show them, or --calendar <id> to target
one specific calendar regardless of its visibility.
Recurring events are expanded into individual occurrences within the range by
default (pass --no-expand to get the raw master events with their RRULE).
--json includes every detail: description, location, attendees, status,
timezone, colour, the calendar id and name, and recurringEventId/isOccurrence
for expanded occurrences.
list events is an alias for agenda.
Agenda options:
| Flag | Description |
| --- | --- |
| --from <date> | Range start (ISO, or today/tomorrow/+3d) |
| --to <date> | Range end (inclusive) |
| --days <n> | Number of days from --from or today |
| --today / --tomorrow | Single day (today is the default) |
| --week / --month | Current week (Mon-Sun) / calendar month |
| --calendar <id> | Only events from this calendar id |
| --search <text> | Filter by title, description or location |
| --include-hidden | Also include calendars you turned off |
| --no-expand | Do not expand recurring events |
| --json | Output as JSON |
List your calendars
Your personal calendar, location/shared calendars and any connected Google/ iCloud/Microsoft/CalDAV accounts:
pulsecalendar calendars
pulsecalendar calendars --jsonUse the printed calendar id with agenda --calendar, free --calendar and
create event --calendar.
Create a calendar event
pulsecalendar create event --title "Lunch with client" \
--start "tomorrow 12:00" --duration 60 --location "Café Central, Amsterdam"
pulsecalendar create event -t "Sprint review" \
--start 2026-07-01T14:00 --end 2026-07-01T15:00 --calendar <id>
pulsecalendar create event -t "Day off" --start 2026-07-04 --all-dayNew timed events that overlap something already on your calendar print a
non-blocking warning (turn it off with --no-conflict-check).
| Flag | Description | Default |
| --- | --- | --- |
| -t, --title | Event title (required) | — |
| -s, --start | Start (ISO or relative, required) | — |
| -e, --end | End (ISO or relative) | start + duration |
| --duration <minutes> | Used when --end is omitted | your settings (60) |
| --all-day | All-day event | — |
| -l, --location | Location | — |
| -d, --description / --description-file | Description (file - = stdin) | — |
| --calendar <id> | Target calendar | your default calendar |
| --no-conflict-check | Skip the overlap warning | — |
| --json | Output the created event as JSON | — |
Your next event
pulsecalendar next # next 3 upcoming events
pulsecalendar next --limit 1 # just the next one
pulsecalendar next --days 7 --jsonFind free time
Find open slots within working hours, in your local timezone. All-day events (e.g. holidays) count as busy by default. Weekends are skipped unless you ask for them.
pulsecalendar free --tomorrow # gaps tomorrow
pulsecalendar free --week --min 60 # 1h+ slots this week
pulsecalendar free --days 5 --work-start 08:00 --work-end 18:00
pulsecalendar free --week --json # for an AI to pick a slot| Flag | Description | Default |
| --- | --- | --- |
| range flags | Same as agenda (--today/--week/--days/--from...) | today |
| --work-start <HH:mm> / --work-end <HH:mm> | Working hours | your settings (09:00 / 17:00) |
| --min <minutes> | Minimum slot length to report | 30 |
| --include-weekends | Include Saturday and Sunday | your settings |
| --ignore-all-day | Don't treat all-day events as busy | off |
| --calendar <id> | Only consider this calendar as busy | all |
| --json | Output slots as JSON | — |
Show, reschedule or delete an event
Get the event id from agenda --json (or next --json), then:
pulsecalendar show event <id> # full details
pulsecalendar show event <id> --json
pulsecalendar update event --id <id> --start "tomorrow 15:00" --end "tomorrow 16:00"
pulsecalendar update event --id <id> --shift 15 # move 15 min later (-15 = earlier)
pulsecalendar update event --id <id> --title "New title" --location "Room 2"
pulsecalendar delete event --id <id>For recurring events the change applies to the whole series (the CLI tells you when that's the case).
| update event flag | Description |
| --- | --- |
| --id <id> | Event id (required) |
| -t, --title / -l, --location / -d, --description | Edit fields |
| -s, --start / -e, --end | New start/end (ISO or relative) |
| --shift <minutes> | Move the whole event by N minutes (+later, -earlier) |
| --calendar <id> | Move to another calendar |
| --json | Output the updated event as JSON |
Create a task
pulsecalendar create task \
--title "Agent: collect disk I/O metrics" \
--product pulseguard \
--priority medium \
--type development \
--category feature_request \
--description "Add per-disk read/write throughput and IOPS to the agent."Long descriptions can be read from a file (or stdin with -):
pulsecalendar create task --title "..." --product pulseguard --description-file ./task.md
cat task.md | pulsecalendar create task --title "..." --description-file -Options:
| Flag | Description | Default |
| --- | --- | --- |
| -t, --title | Task title (required) | — |
| -p, --product | general, pulseguard, pulsefiles, pulseqr, pulsecalendar, pulsesupport, pulsemail, ipulse | pulseguard |
| -d, --description | Markdown description | — |
| --description-file | Read description from a file (- = stdin) | — |
| --priority | high, medium, low | medium |
| --status | not_started, in_progress, ready_for_test, done | not_started |
| --type | one or more of general, development, marketing | development |
| --category | one or more of bug, refinement, feature_request | — |
| --relation-number | linked customer relation number | — |
| --due | due date (ISO) | — |
| --json | print the created task as JSON | — |
List tasks
pulsecalendar list tasks
pulsecalendar list tasks --status in_progress
pulsecalendar list tasks --search agent --include-done
pulsecalendar list tasks --jsonOther commands
pulsecalendar whoami # show the logged-in account
pulsecalendar logout # remove the stored tokenHow auth works
The CLI is a public OAuth client (pulsecalendar-cli) on the iPulse identity
provider, using authorization code + PKCE with a loopback redirect (same
pattern as gh auth login and the PulseEnv CLI):
- The CLI starts a one-shot HTTP server on
127.0.0.1:47655. - It opens
https://ipulse.one/api/oauth/authorizein your browser with a PKCE challenge. - iPulse signs you in and redirects back to
http://127.0.0.1:47655/callbackwith an authorization code. - The CLI exchanges the code (plus PKCE verifier) for access and refresh tokens and stores them locally.
The PulseCalendar API verifies these RS256 tokens against the iPulse JWKS and
maps your iPulse account to your PulseCalendar user by e-mail. New tasks are
assigned to you by default, with priority medium, type development, status
not_started and the current sprint, so AI agents can create a task with just
a --title.
Develop
npm install
npm run dev -- create task --title "test" --product pulseguard # run from source via tsx
npm run build # emit dist/