{
  "schema": "snappy-card/1",
  "skill": "snappy-calendar",
  "tier": "public",
  "origin_tier": "base",
  "purpose": "You handle Snappy's Google Calendar: reading events, checking availability, creating meetings, pre-call prep, weekly planning, time blocking, and post-meeting follow-up. Direct Google Calendar API v3 via service account JWT auth. No Xano middleware.",
  "verbs": [
    {
      "name": "availability",
      "args": [
        "days?"
      ],
      "effect": "read",
      "firstCall": "npx tsx ~/.claude/skills/snappy-calendar/api.ts availability"
    },
    {
      "name": "by-attendee",
      "args": [
        "email"
      ],
      "effect": "read",
      "firstCall": "npx tsx ~/.claude/skills/snappy-calendar/api.ts by-attendee <email>"
    },
    {
      "name": "create",
      "args": [
        "event-json"
      ],
      "effect": "write",
      "firstCall": "npx tsx ~/.claude/skills/snappy-calendar/api.ts create '[\"<event>\"]'"
    },
    {
      "name": "delete",
      "args": [
        "event-id"
      ],
      "effect": "delete",
      "firstCall": "npx tsx ~/.claude/skills/snappy-calendar/api.ts delete <event-id>"
    },
    {
      "name": "events",
      "args": [
        "days?"
      ],
      "effect": "read",
      "firstCall": "npx tsx ~/.claude/skills/snappy-calendar/api.ts events"
    },
    {
      "name": "event",
      "args": [
        "event-id"
      ],
      "effect": "read",
      "firstCall": "npx tsx ~/.claude/skills/snappy-calendar/api.ts event <event-id>"
    },
    {
      "name": "list",
      "args": [
        "days?"
      ],
      "effect": "read",
      "firstCall": "npx tsx ~/.claude/skills/snappy-calendar/api.ts list"
    },
    {
      "name": "get",
      "args": [
        "event-id"
      ],
      "effect": "read",
      "firstCall": "npx tsx ~/.claude/skills/snappy-calendar/api.ts get <event-id>"
    },
    {
      "name": "propose",
      "args": [
        "days?",
        "duration?"
      ],
      "effect": "draft",
      "firstCall": "npx tsx ~/.claude/skills/snappy-calendar/api.ts propose"
    },
    {
      "name": "today",
      "args": [],
      "effect": "read",
      "firstCall": "npx tsx ~/.claude/skills/snappy-calendar/api.ts today"
    },
    {
      "name": "update",
      "args": [
        "event-id",
        "event-json"
      ],
      "effect": "write",
      "firstCall": "npx tsx ~/.claude/skills/snappy-calendar/api.ts update <event-id> '[\"<event>\"]'"
    }
  ],
  "faces": [],
  "agents": [],
  "uses": [
    "snappy-ops",
    "snappy-scheduling",
    "snappy-sales",
    "snappy-knowledge",
    "snappy-email",
    "snappy-slack"
  ],
  "used_by": [
    "snappy-imessage",
    "snappy-whatsapp"
  ],
  "checks": {
    "pass": 48,
    "fail": 6,
    "defer": 7,
    "line": "48 of 54 checks pass",
    "failing": [
      {
        "id": 4,
        "rule": "Near-neighbour descriptions cross-reference each other",
        "says": "near neighbours not named: snappy-client-feisst, snappy-specwatch"
      },
      {
        "id": 5,
        "rule": "Description is valid, third-person, and says what plus when",
        "says": "first/second person"
      },
      {
        "id": 40,
        "rule": "Metadata, skill body, and resources follow three-level budgets",
        "says": "metadata ~195 tokens; body ~4199 tokens"
      },
      {
        "id": 54,
        "rule": "At least three eval scenarios precede ready status",
        "says": "0 eval scenario(s); ready=true"
      },
      {
        "id": 55,
        "rule": "Eval scenarios are multi-call with ground truth",
        "says": "eval manifest missing"
      },
      {
        "id": 57,
        "rule": "Eval manifest contains a disjoint holdout",
        "says": "0 disjoint holdout scenario(s)"
      }
    ]
  },
  "coverage": null,
  "spec": null,
  "evals": null,
  "files": [
    "AGENTS.md",
    "SKILL.md",
    "api.ts",
    "entities.json",
    "face.test.ts",
    "faces/components/calendar-event-preview.tsx",
    "faces/components/calendar-shared.tsx",
    "faces/components/calendar-week-preview.css",
    "faces/components/calendar-week-preview.tsx",
    "faces/family.tsx",
    "faces/fixtures/calendar-event.json",
    "faces/fixtures/calendar-week.json",
    "queries.md",
    "refusals.test.ts"
  ],
  "total_size": 139352,
  "checksum": "sha256:4a171a239f4cb67b1fefd46c6378d7e4a0ac2eac010ffac9c0fef615adac9dd0",
  "built_at": "2026-09-09T22:08:19.898Z",
  "openapi": {
    "openapi": "3.1.0",
    "info": {
      "title": "snappy-calendar",
      "version": "0.0.0",
      "description": "Google Calendar operations for Snappy -- view events, create meetings, check availability, schedule calls, pre-call prep, post-meeting follow-up, weekly planning, time blocking. Xano API for all calendar CRUD. icalBuddy for fast read-only fallback. Feeds the morning briefing in snappy-ops, attendee data into snappy-knowledge, prospect context into snappy-sales, and meeting summaries through snappy-update. Triggers on: calendar, schedule, meeting, event, free time, availability, book a call, what's on today, next meeting, block time, when am I free, morning calendar, weekly planning, pre-call prep, post-meeting, find a slot, propose times, deep work, time block, meeting prep, what's my week, review week, plan the week, ical, icalbuddy, google calendar, calendar event."
    },
    "x-snappy-transport": "cli",
    "servers": [
      {
        "url": "npx tsx ~/.claude/skills/snappy-calendar/api.ts",
        "description": "The hand itself. Every path is a verb word, every query or body key an argument."
      }
    ],
    "paths": {
      "/availability": {
        "get": {
          "operationId": "snappy_calendar_availability",
          "summary": "snappy-calendar availability",
          "x-snappy-effect": "read",
          "x-snappy-annotations": {
            "readOnlyHint": true,
            "destructiveHint": false,
            "idempotentHint": false,
            "openWorldHint": true
          },
          "parameters": [
            {
              "name": "days",
              "in": "query",
              "required": false,
              "schema": {
                "type": "integer",
                "description": "How many days ahead the window reaches; the read starts today",
                "default": 1,
                "x-snappy-position": 0
              }
            }
          ],
          "responses": {
            "200": {
              "description": "The verb's own answer, as printed by `--json`."
            }
          }
        }
      },
      "/by-attendee": {
        "get": {
          "operationId": "snappy_calendar_by_attendee",
          "summary": "snappy-calendar by-attendee",
          "x-snappy-effect": "read",
          "x-snappy-annotations": {
            "readOnlyHint": true,
            "destructiveHint": false,
            "idempotentHint": false,
            "openWorldHint": true
          },
          "parameters": [
            {
              "name": "email",
              "in": "query",
              "required": true,
              "schema": {
                "type": "string",
                "description": "The attendee's email address; every event they are on is returned",
                "x-snappy-position": 0
              }
            }
          ],
          "responses": {
            "200": {
              "description": "The verb's own answer, as printed by `--json`."
            }
          }
        }
      },
      "/create": {
        "post": {
          "operationId": "snappy_calendar_create",
          "summary": "snappy-calendar create",
          "x-snappy-effect": "write",
          "x-snappy-annotations": {
            "readOnlyHint": false,
            "destructiveHint": false,
            "idempotentHint": false,
            "openWorldHint": true
          },
          "requestBody": {
            "required": true,
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "event-json": {
                      "type": "string",
                      "description": "The event as a JSON object in Google Calendar's own event shape: summary, start, end, attendees",
                      "x-snappy-position": 0
                    }
                  },
                  "required": [
                    "event-json"
                  ]
                }
              }
            }
          },
          "responses": {
            "200": {
              "description": "The verb's own answer, as printed by `--json`."
            }
          }
        }
      },
      "/delete": {
        "post": {
          "operationId": "snappy_calendar_delete",
          "summary": "snappy-calendar delete",
          "x-snappy-effect": "delete",
          "x-snappy-annotations": {
            "readOnlyHint": false,
            "destructiveHint": true,
            "idempotentHint": false,
            "openWorldHint": true
          },
          "requestBody": {
            "required": true,
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "event-id": {
                      "type": "string",
                      "description": "The Google Calendar event id, from an `events` row's `id`",
                      "x-snappy-position": 0
                    }
                  },
                  "required": [
                    "event-id"
                  ]
                }
              }
            }
          },
          "responses": {
            "200": {
              "description": "The verb's own answer, as printed by `--json`."
            }
          }
        }
      },
      "/events": {
        "get": {
          "operationId": "snappy_calendar_events",
          "summary": "snappy-calendar events",
          "x-snappy-effect": "read",
          "x-snappy-annotations": {
            "readOnlyHint": true,
            "destructiveHint": false,
            "idempotentHint": false,
            "openWorldHint": true
          },
          "parameters": [
            {
              "name": "days",
              "in": "query",
              "required": false,
              "schema": {
                "type": "integer",
                "description": "How many days ahead the window reaches; the read starts today",
                "default": 1,
                "x-snappy-position": 0
              }
            },
            {
              "name": "json",
              "in": "query",
              "required": false,
              "schema": {
                "x-snappy-flag": "--json"
              }
            },
            {
              "name": "limit",
              "in": "query",
              "required": false,
              "schema": {
                "type": "integer",
                "description": "How many events the window returns, earliest first. The count is the FLAG --limit, never a positional word; default 100, ceiling 2500",
                "default": 100,
                "minimum": 1,
                "maximum": 2500,
                "x-snappy-flag": "--limit"
              }
            }
          ],
          "responses": {
            "200": {
              "description": "The verb's own answer, as printed by `--json`."
            }
          }
        }
      },
      "/event": {
        "get": {
          "operationId": "snappy_calendar_event",
          "summary": "snappy-calendar event",
          "x-snappy-effect": "read",
          "x-snappy-annotations": {
            "readOnlyHint": true,
            "destructiveHint": false,
            "idempotentHint": false,
            "openWorldHint": true
          },
          "parameters": [
            {
              "name": "event-id",
              "in": "query",
              "required": true,
              "schema": {
                "type": "string",
                "description": "The Google Calendar event id, from an `events` row's `id`",
                "x-snappy-position": 0
              }
            },
            {
              "name": "json",
              "in": "query",
              "required": false,
              "schema": {
                "x-snappy-flag": "--json"
              }
            }
          ],
          "responses": {
            "200": {
              "description": "The verb's own answer, as printed by `--json`."
            }
          }
        }
      },
      "/list": {
        "get": {
          "operationId": "snappy_calendar_list",
          "summary": "snappy-calendar list",
          "x-snappy-effect": "read",
          "x-snappy-annotations": {
            "readOnlyHint": true,
            "destructiveHint": false,
            "idempotentHint": false,
            "openWorldHint": true
          },
          "parameters": [
            {
              "name": "days",
              "in": "query",
              "required": false,
              "schema": {
                "type": "integer",
                "description": "How many days ahead the window reaches; the read starts today",
                "default": 1,
                "x-snappy-position": 0
              }
            },
            {
              "name": "json",
              "in": "query",
              "required": false,
              "schema": {
                "x-snappy-flag": "--json"
              }
            },
            {
              "name": "limit",
              "in": "query",
              "required": false,
              "schema": {
                "type": "integer",
                "description": "How many events the window returns, earliest first. The count is the FLAG --limit, never a positional word; default 100, ceiling 2500",
                "default": 100,
                "minimum": 1,
                "maximum": 2500,
                "x-snappy-flag": "--limit"
              }
            }
          ],
          "responses": {
            "200": {
              "description": "The verb's own answer, as printed by `--json`."
            }
          }
        }
      },
      "/get": {
        "get": {
          "operationId": "snappy_calendar_get",
          "summary": "snappy-calendar get",
          "x-snappy-effect": "read",
          "x-snappy-annotations": {
            "readOnlyHint": true,
            "destructiveHint": false,
            "idempotentHint": false,
            "openWorldHint": true
          },
          "parameters": [
            {
              "name": "event-id",
              "in": "query",
              "required": true,
              "schema": {
                "type": "string",
                "description": "The Google Calendar event id, from an `events` row's `id`",
                "x-snappy-position": 0
              }
            },
            {
              "name": "json",
              "in": "query",
              "required": false,
              "schema": {
                "x-snappy-flag": "--json"
              }
            }
          ],
          "responses": {
            "200": {
              "description": "The verb's own answer, as printed by `--json`."
            }
          }
        }
      },
      "/propose": {
        "post": {
          "operationId": "snappy_calendar_propose",
          "summary": "snappy-calendar propose",
          "x-snappy-effect": "draft",
          "x-snappy-annotations": {
            "readOnlyHint": false,
            "destructiveHint": false,
            "idempotentHint": false,
            "openWorldHint": true
          },
          "requestBody": {
            "required": false,
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "days": {
                      "type": "integer",
                      "description": "How many days ahead to search for free slots",
                      "default": 3,
                      "x-snappy-position": 0
                    },
                    "duration": {
                      "type": "integer",
                      "description": "Meeting length in minutes",
                      "default": 30,
                      "x-snappy-position": 1
                    }
                  }
                }
              }
            }
          },
          "responses": {
            "200": {
              "description": "The verb's own answer, as printed by `--json`."
            }
          }
        }
      },
      "/today": {
        "get": {
          "operationId": "snappy_calendar_today",
          "summary": "snappy-calendar today",
          "x-snappy-effect": "read",
          "x-snappy-annotations": {
            "readOnlyHint": true,
            "destructiveHint": false,
            "idempotentHint": false,
            "openWorldHint": true
          },
          "parameters": [
            {
              "name": "json",
              "in": "query",
              "required": false,
              "schema": {
                "x-snappy-flag": "--json"
              }
            }
          ],
          "responses": {
            "200": {
              "description": "The verb's own answer, as printed by `--json`."
            }
          }
        }
      },
      "/update": {
        "post": {
          "operationId": "snappy_calendar_update",
          "summary": "snappy-calendar update",
          "x-snappy-effect": "write",
          "x-snappy-annotations": {
            "readOnlyHint": false,
            "destructiveHint": false,
            "idempotentHint": false,
            "openWorldHint": true
          },
          "requestBody": {
            "required": true,
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "event-id": {
                      "type": "string",
                      "description": "The Google Calendar event id, from an `events` row's `id`",
                      "x-snappy-position": 0
                    },
                    "event-json": {
                      "type": "string",
                      "description": "The event as a JSON object in Google Calendar's own event shape: summary, start, end, attendees",
                      "x-snappy-position": 1
                    }
                  },
                  "required": [
                    "event-id",
                    "event-json"
                  ]
                }
              }
            }
          },
          "responses": {
            "200": {
              "description": "The verb's own answer, as printed by `--json`."
            }
          }
        }
      }
    },
    "components": {
      "schemas": {
        "SnappyRefusal": {
          "type": "object",
          "required": [
            "outcome",
            "code",
            "message"
          ],
          "properties": {
            "outcome": {
              "type": "string",
              "const": "refused"
            },
            "code": {
              "type": "string",
              "description": "A row of the closed refusal table."
            },
            "message": {
              "type": "string"
            },
            "fix": {
              "type": "string"
            }
          }
        }
      }
    },
    "x-snappy-requires": [
      "GOOGLE_SERVICE_ACCOUNT_EMAIL",
      "GOOGLE_SERVICE_ACCOUNT_KEY"
    ]
  }
}