{
  "name": "calendar",
  "kind": "registry",
  "title": "Calendar",
  "description": "Your upcoming events with the current one marked, and a meeting about to start at the top of the panel, one key to join the call. Add events with a form or one typed line like `standup tomorrow 10:00`.",
  "version": "0.1.0",
  "icon": {
    "tile": {
      "glyph": "󰃭",
      "bg": "red"
    }
  },
  "author": "pal",
  "spec": "github:zcag/pal/extensions/calendar@v0.17.4",
  "source": "https://github.com/zcag/pal-extensions/tree/HEAD/calendar",
  "commit": "4d2559cf9c04d0133c97d7c897f19a14acb9eace",
  "manifest": {
    "name": "calendar",
    "title": "Calendar",
    "description": "Your upcoming events with the current one marked, and a meeting about to start at the top of the panel, one key to join the call. Add events with a form or one typed line like `standup tomorrow 10:00`.",
    "keywords": [
      "cal"
    ],
    "version": "0.1.0",
    "icon": {
      "tile": {
        "glyph": "󰃭",
        "bg": "red"
      }
    },
    "author": "pal",
    "repo": "bundled",
    "license": "MIT",
    "settings": [
      {
        "kind": "select",
        "id": "source",
        "label": "Source",
        "description": "Where the events come from. Auto is Google once an account is listed below, else the system calendar (EventKit on macOS, khal on Linux).",
        "options": [
          {
            "id": "auto",
            "title": "Auto"
          },
          {
            "id": "system",
            "title": "System calendar"
          },
          {
            "id": "google",
            "title": "Google Calendar"
          }
        ],
        "default": "auto"
      },
      {
        "kind": "list",
        "id": "accounts",
        "label": "Google accounts",
        "placeholder": "work = gcloud auth application-default print-access-token",
        "description": "One per line as `name = command`: the command prints an access token for the Calendar API (a bare token, or the JSON of an OAuth endpoint with access_token and expires_in). The command owns the secret; pal keeps the token in memory until it expires. In the config file an entry may be a table { name, token_command, calendars } to read calendars other than the primary.",
        "default": []
      },
      {
        "kind": "list",
        "id": "calendars",
        "label": "Calendars",
        "placeholder": "Work",
        "description": "Calendar names (or ids) to show; empty shows every calendar. The filter dropdown narrows further.",
        "default": []
      },
      {
        "kind": "number",
        "id": "days",
        "label": "Days ahead",
        "description": "How many days from today My Schedule lists.",
        "min": 1,
        "max": 90,
        "step": 1,
        "unit": "days",
        "default": 7
      },
      {
        "kind": "boolean",
        "id": "hide_declined",
        "label": "Hide declined",
        "text": "Leave out invitations you declined",
        "default": true
      },
      {
        "kind": "number",
        "id": "horizon_hours",
        "label": "Bar horizon",
        "description": "The bar item shows the next event only when it starts within this many hours; nothing sooner, no item.",
        "min": 1,
        "max": 48,
        "step": 1,
        "unit": "hours",
        "default": 10
      },
      {
        "kind": "boolean",
        "id": "hide_all_day",
        "label": "Skip all-day events on the bar",
        "text": "The bar item speaks for timed events only",
        "default": true
      },
      {
        "kind": "number",
        "id": "call_lead",
        "label": "Call row from",
        "description": "An event with a call gets a Join row at the top of pal this many minutes before it starts, until ten minutes in.",
        "min": 1,
        "max": 30,
        "step": 1,
        "unit": "min",
        "default": 5
      },
      {
        "kind": "number",
        "id": "default_length",
        "label": "Quick Add length",
        "description": "How long an event typed without an end or a `for` lasts.",
        "min": 5,
        "max": 480,
        "step": 5,
        "unit": "min",
        "default": 30
      }
    ],
    "store": {
      "tagline": "Today at a glance, one key to join the call",
      "category": "productivity",
      "features": [
        "Today and My Schedule: events in order, each tagged `in 12 min`, `now` or `over`",
        "`enter` joins the Zoom, Meet, Teams or Webex call, or opens the event",
        "A call about to start sits at the top of the panel before you type anything",
        "The next event on the menu bar, amber inside 15 minutes and red inside 5; a click joins",
        "Add events by form or one line (`dentist fri 2pm-3pm`); delete one after a confirmation",
        "Reads Calendar.app's accounts on macOS, `khal` on Linux, or Google Calendar directly"
      ],
      "permissions": [
        "calendars"
      ],
      "platforms": [
        "macos",
        "linux"
      ],
      "screenshots": [
        {
          "file": "1-schedule.png",
          "caption": "What is left of today and the days after, the next event tagged with how soon, calls tagged Join"
        },
        {
          "file": "2-detail.png",
          "caption": "The detail pane: when and the calendar over the title, your reply, the notes, then the call, the organizer and the attendees with their replies"
        },
        {
          "file": "3-new.png",
          "caption": "New event: a title, a day in words, the times from the next quarter hour, the calendar"
        },
        {
          "file": "4-today.png",
          "caption": "Today: the whole day in order, what is over greyed, the rest with how long until it starts"
        },
        {
          "file": "5-quick.png",
          "caption": "Quick Add: a line typed, the event read back with its day, time, place and calendar before Enter adds it"
        },
        {
          "file": "bar-menubar.png",
          "caption": "On the menu bar: the next event and how long until it, the glyph amber inside fifteen minutes, a dot for a call to join",
          "kind": "bar"
        },
        {
          "file": "bar-menubar-urgent.png",
          "caption": "Inside five minutes the glyph turns red",
          "kind": "bar"
        },
        {
          "file": "bar-popover.png",
          "caption": "A click opens the day: what is still to come with the time, the place and the people, Join on the calls, tomorrow folded under its header",
          "kind": "bar",
          "box": [
            326,
            64,
            840,
            806
          ]
        },
        {
          "file": "bar-popover-now.png",
          "caption": "While a call runs its row sits on a card with what is left of it, the strip green; Enter joins",
          "kind": "bar",
          "box": [
            252,
            64,
            840,
            806
          ]
        },
        {
          "file": "bar-popover-tomorrow.png",
          "caption": "Late in the day: what is left, and t opens tomorrow in the same shape; the arrows walk the rows",
          "kind": "bar",
          "box": [
            358,
            64,
            840,
            886
          ]
        },
        {
          "file": "bar-sketchybar.png",
          "caption": "On sketchybar: the same item, amber with the call's dot",
          "kind": "bar"
        }
      ],
      "actions": [
        {
          "title": "Join call",
          "description": "Opens the meeting link; first when the event has one.",
          "keys": "enter"
        },
        {
          "title": "Open in Calendar",
          "description": "Shows the event in Calendar.app (macOS), or opens it in Google Calendar for a Google account.",
          "keys": "enter"
        },
        {
          "title": "Copy conference link",
          "keys": "cmd+shift+c"
        },
        {
          "title": "Copy event details",
          "description": "Title, when, where and the link as text.",
          "keys": "cmd+c"
        },
        {
          "title": "Delete event",
          "description": "Asks first; on a repeating event only this occurrence goes (macOS).",
          "keys": "ctrl+x"
        },
        {
          "title": "New event",
          "description": "The form, then the event in the chosen calendar.",
          "keys": "enter"
        },
        {
          "title": "Add event",
          "description": "Quick Add: the line as typed becomes the event.",
          "keys": "enter"
        },
        {
          "title": "Grant access",
          "description": "On the permission row: the system prompt, or System Settings when it was denied.",
          "keys": "enter"
        }
      ]
    },
    "palettes": {
      "schedule": {
        "title": "My Schedule",
        "kind": "live",
        "remember": false,
        "ttl": 60,
        "description": "The next days' events in time order, sectioned by day, the current or next one tagged; a New event row at the end (system calendar).",
        "keys": [
          {
            "keys": "enter",
            "title": "Join the call, else open in Calendar"
          },
          {
            "keys": "cmd+shift+c",
            "title": "Copy the conference link"
          },
          {
            "keys": "cmd+c",
            "title": "Copy the event details"
          },
          {
            "keys": "ctrl+x",
            "title": "Delete the event"
          }
        ]
      },
      "today": {
        "title": "Today",
        "kind": "live",
        "remember": false,
        "ttl": 60,
        "description": "The day's events in order with the time, how long, and where each stands (`in 12 min`, `now, 25 min left`, `over`); tomorrow's once today is done; what the bar item opens. At the root, a Join row for a call from a few minutes before it starts until ten minutes in.",
        "keys": [
          {
            "keys": "enter",
            "title": "Join the call, else open in Calendar"
          },
          {
            "keys": "cmd+shift+c",
            "title": "Copy the conference link"
          },
          {
            "keys": "cmd+c",
            "title": "Copy the event details"
          },
          {
            "keys": "cmd+i",
            "title": "Details: the description, the attendees with their replies, the link"
          }
        ]
      },
      "quick": {
        "title": "Quick Add Event",
        "kind": "input",
        "fallback": "Add “{query}” to the calendar",
        "description": "One line into an event: a title, then a day (`tomorrow`, `fri`, `next tue`, `20 sep`, `2026-09-20`), a time or a range (`10:00`, `2pm-3pm`, `14:00 to 15:30`), `for 45m`, `at \u003cplace\u003e`, `@ \u003ccalendar\u003e` (or `in \u003ccalendar\u003e` when one starts with the word), `all day`. No time: all day; no day: today, or tomorrow once the time has passed. The row shows the event read back as you type; Enter adds it. At the root a query nothing matched gets an Add fallback row.",
        "keys": [
          {
            "keys": "enter",
            "title": "Add the event as read"
          }
        ]
      }
    },
    "states": {
      "phase": {
        "description": "The next event's time state: far, near, warning, critical, running, or none within the horizon",
        "kind": "string"
      },
      "minutes": {
        "description": "Minutes until the next event starts (negative while it runs)",
        "kind": "number"
      },
      "call": {
        "description": "The next event has a call to join",
        "kind": "boolean"
      }
    },
    "bar": {
      "upcoming": {
        "title": "Upcoming",
        "description": "The next event's name with `in 12m` beside it, `25m left` while it runs (and `in 8m` for the one due next); hidden when nothing starts within the horizon; a dot when there is a call to join. The colour follows the rules: muted far off and near, amber from Warning from, red from Critical from, green while it runs. A click joins the call, or opens Calendar; a hover peek opens the day with Join on the calls, the running event on a card, tomorrow folded.",
        "mocks": {
          "far": {
            "title": "Starts in 3 hours",
            "item": {
              "icon": "󰃭",
              "title": "Project review",
              "segments": [
                {
                  "id": "when",
                  "text": "in 3h"
                }
              ],
              "color": "muted",
              "badge": "dot"
            }
          },
          "near": {
            "title": "Starts in 45 minutes",
            "item": {
              "icon": "󰃭",
              "title": "Project review",
              "segments": [
                {
                  "id": "when",
                  "text": "in 45m"
                }
              ],
              "color": "muted",
              "badge": "dot"
            }
          },
          "warning": {
            "title": "Starts in 12 minutes",
            "item": {
              "icon": "󰃭",
              "title": "Project review",
              "segments": [
                {
                  "id": "when",
                  "text": "in 12m"
                }
              ],
              "color": "amber",
              "badge": "dot"
            }
          },
          "critical": {
            "title": "Starts in 4 minutes",
            "item": {
              "icon": "󰃭",
              "title": "Project review",
              "segments": [
                {
                  "id": "when",
                  "text": "in 4m"
                }
              ],
              "color": "red",
              "badge": "dot"
            }
          },
          "running": {
            "title": "In progress, 25 minutes left",
            "item": {
              "icon": "󰃭",
              "title": "Project review",
              "segments": [
                {
                  "id": "when",
                  "text": "25m left"
                }
              ],
              "color": "green",
              "badge": "dot"
            }
          },
          "running-next": {
            "title": "In progress, the next one in 8 minutes",
            "item": {
              "icon": "󰃭",
              "title": "Project review",
              "segments": [
                {
                  "id": "when",
                  "text": "12m left"
                },
                {
                  "id": "next",
                  "text": "in 8m",
                  "color": "amber",
                  "tooltip": "Design sync, 11:00 – 11:30 (Team)"
                }
              ],
              "color": "green",
              "badge": "dot",
              "tooltip": "Project review, 10:20 – 10:50 (Work), Enter joins; then Design sync, 11:00 – 11:30 (Team)"
            }
          }
        },
        "refresh": {
          "every": 300,
          "on": [
            "minute",
            "wake",
            "network"
          ]
        },
        "keys": [
          {
            "keys": "enter",
            "title": "Join the focused event's call, else open it in Calendar (Google Calendar for a Google account)"
          },
          {
            "keys": "j",
            "title": "Join the next call"
          },
          {
            "keys": "t",
            "title": "Show or fold tomorrow"
          },
          {
            "keys": "o",
            "title": "Open Calendar (the day's page on calendar.google.com for a Google account)"
          },
          {
            "keys": "r",
            "title": "Refresh"
          },
          {
            "keys": "cmd+c",
            "title": "Copy the focused event's details"
          },
          {
            "keys": "cmd+shift+c",
            "title": "Copy the focused event's conference link"
          },
          {
            "keys": "up, down",
            "title": "Move between the rows; a click on a row focuses it, a click on Join joins it"
          }
        ],
        "rules": [
          {
            "id": "far",
            "when": "calendar.phase == 'far'",
            "description": "Beyond Near from: nothing pressing.",
            "color": "muted"
          },
          {
            "id": "near",
            "when": "calendar.phase == 'near'",
            "description": "Inside Near from, before Warning from.",
            "color": "muted"
          },
          {
            "id": "warning",
            "when": "calendar.phase == 'warning'",
            "description": "Inside Warning from.",
            "color": "amber"
          },
          {
            "id": "critical",
            "when": "calendar.phase == 'critical'",
            "description": "Inside Critical from: about to start.",
            "color": "red"
          },
          {
            "id": "running",
            "when": "calendar.phase == 'running'",
            "description": "Under way: what is left of it.",
            "color": "green"
          }
        ],
        "settings": [
          {
            "kind": "number",
            "id": "near_minutes",
            "label": "Near from",
            "description": "Inside this many minutes, Upcoming uses its near appearance. Warning and critical cutoffs below still take precedence.",
            "min": 1,
            "max": 720,
            "step": 1,
            "unit": "min",
            "default": 60
          },
          {
            "kind": "number",
            "id": "warn_minutes",
            "label": "Warning from",
            "description": "The bar item uses its warning appearance this many minutes before the event.",
            "min": 1,
            "max": 120,
            "step": 1,
            "unit": "min",
            "default": 15
          },
          {
            "kind": "number",
            "id": "urgent_minutes",
            "label": "Critical from",
            "description": "The bar item uses its critical appearance this many minutes before the event.",
            "min": 0,
            "max": 60,
            "step": 1,
            "unit": "min",
            "default": 5
          }
        ]
      }
    }
  },
  "playable": false,
  "updated_at": "2026-11-02T04:38:11Z",
  "url": "https://pal.cagdas.io/extensions/calendar",
  "tagline": "Today at a glance, one key to join the call",
  "category": "productivity",
  "screenshots": [
    "https://pal.cagdas.io/extensions/calendar/screenshots/1-schedule-dark.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/1-schedule.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/2-detail-dark.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/2-detail.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/3-new-dark.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/3-new.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/4-today-dark.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/4-today.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/5-quick-dark.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/5-quick.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/bar-menubar-dark.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/bar-menubar-urgent-dark.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/bar-menubar-urgent.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/bar-menubar.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/bar-popover-dark.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/bar-popover-now-dark.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/bar-popover-now.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/bar-popover-tomorrow-dark.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/bar-popover-tomorrow.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/bar-popover.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/bar-sketchybar-dark.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/bar-sketchybar.png"
  ],
  "panel_screenshots": [
    "https://pal.cagdas.io/extensions/calendar/screenshots/1-schedule.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/2-detail.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/3-new.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/4-today.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/5-quick.png"
  ],
  "bar_screenshots": [
    "https://pal.cagdas.io/extensions/calendar/screenshots/bar-menubar-urgent.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/bar-menubar.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/bar-popover-now.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/bar-popover-tomorrow.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/bar-popover.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/bar-sketchybar.png"
  ],
  "panel_screenshots_dark": [
    "https://pal.cagdas.io/extensions/calendar/screenshots/1-schedule-dark.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/2-detail-dark.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/3-new-dark.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/4-today-dark.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/5-quick-dark.png"
  ],
  "bar_screenshots_dark": [
    "https://pal.cagdas.io/extensions/calendar/screenshots/bar-menubar-urgent-dark.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/bar-menubar-dark.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/bar-popover-now-dark.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/bar-popover-tomorrow-dark.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/bar-popover-dark.png",
    "https://pal.cagdas.io/extensions/calendar/screenshots/bar-sketchybar-dark.png"
  ],
  "has_bar": true,
  "bar_items": [
    {
      "id": "upcoming",
      "title": "Upcoming",
      "description": "The next event's name with `in 12m` beside it, `25m left` while it runs (and `in 8m` for the one due next); hidden when nothing starts within the horizon; a dot when there is a call to join. The colour follows the rules: muted far off and near, amber from Warning from, red from Critical from, green while it runs. A click joins the call, or opens Calendar; a hover peek opens the day with Join on the calls, the running event on a card, tomorrow folded.",
      "refresh": {
        "every": 300,
        "on": [
          "minute",
          "wake",
          "network"
        ]
      },
      "refresh_words": "every 5 min, every minute, on wake, when the network is back"
    }
  ],
  "has_links": false,
  "links": [],
  "multi": false,
  "has_readme": true
}
