{
  "schema": "snappy-card/1",
  "skill": "snappy-scheduling",
  "tier": "public",
  "origin_tier": "base",
  "purpose": "You are booking a meeting. This skill handles the negotiation (propose, confirm, invite). The final event creation goes through `snappy-calendar`.",
  "verbs": [
    {
      "name": "available",
      "args": [],
      "effect": "read",
      "firstCall": "npx tsx ~/.claude/skills/snappy-scheduling/api.ts available"
    },
    {
      "name": "propose",
      "args": [
        "days?",
        "duration?"
      ],
      "effect": "draft",
      "firstCall": "npx tsx ~/.claude/skills/snappy-scheduling/api.ts propose"
    }
  ],
  "faces": [],
  "agents": [],
  "uses": [],
  "used_by": [
    "snappy-calendar"
  ],
  "checks": {
    "pass": 40,
    "fail": 5,
    "defer": 16,
    "line": "40 of 45 checks pass",
    "failing": [
      {
        "id": 8,
        "rule": "Skill body and reference graph stay within disclosure budgets",
        "says": "257 lines; ~2882 tokens; deep reference ../snappy-settings/SKILL.md; ../snappy-settings/SKILL.md >100 lines without ToC; deep reference ../snappy-calendar/queries.md; deep reference ../snappy-knowledge/endpoints.md; deep reference ../snappy-settings/SKILL.md; ../snappy-settings/SKILL.md >100 lines without ToC"
      },
      {
        "id": 40,
        "rule": "Metadata, skill body, and resources follow three-level budgets",
        "says": "metadata ~209 tokens; body ~2882 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",
    "references.md",
    "refusals.test.ts",
    "schedule-pick.test.ts",
    "workflows.md"
  ],
  "total_size": 47331,
  "checksum": "sha256:1cb6fb401e82ea60339ae614ca3f4b0a5c9fd402a6dd5e700700d31f84a3f7cf",
  "built_at": "2026-09-09T22:10:43.479Z",
  "openapi": {
    "openapi": "3.1.0",
    "info": {
      "title": "snappy-scheduling",
      "version": "0.0.0",
      "description": "Meeting scheduling for Snappy -- the negotiation layer above the calendar. Handles proposing times, sending invites, parsing RSVPs, resolving conflicts, multi-attendee coordination, scheduling links (Cal.com), time zone math, and the back-and-forth required to actually book a meeting. Different from snappy-calendar (which is the record layer -- events, availability, CRUD). scheduling = negotiation. calendar = record. Calls into snappy-calendar for the final create. Triggers on: schedule meeting, book a call, propose times, find a time, send invite, send calendar invite, ICS file, scheduling link, calendly, cal.com, reschedule, cancel meeting, time zone, TZ math, conflict resolution, multi attendee, group call, find slot, available times, meeting proposal, hold the time, confirm the time, RSVP, accept invite, decline invite."
    },
    "x-snappy-transport": "cli",
    "servers": [
      {
        "url": "npx tsx ~/.claude/skills/snappy-scheduling/api.ts",
        "description": "The hand itself. Every path is a verb word, every query or body key an argument."
      }
    ],
    "paths": {
      "/available": {
        "get": {
          "operationId": "snappy_scheduling_available",
          "summary": "snappy-scheduling available",
          "x-snappy-effect": "read",
          "x-snappy-annotations": {
            "readOnlyHint": true,
            "destructiveHint": false,
            "idempotentHint": false,
            "openWorldHint": true
          },
          "parameters": [],
          "responses": {
            "200": {
              "description": "The verb's own answer, as printed by `--json`."
            }
          }
        }
      },
      "/propose": {
        "post": {
          "operationId": "snappy_scheduling_propose",
          "summary": "snappy-scheduling 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 slots",
                      "x-snappy-position": 0
                    },
                    "duration": {
                      "type": "integer",
                      "description": "Meeting length in minutes",
                      "x-snappy-position": 1
                    },
                    "json": {
                      "x-snappy-flag": "--json"
                    },
                    "about": {
                      "type": "string",
                      "description": "What the meeting IS, in the asker's own words; it becomes the question on the face",
                      "x-snappy-flag": "--about"
                    }
                  }
                }
              }
            }
          },
          "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",
      "XANO_METADATA_TOKEN"
    ]
  }
}