{
  "schema": "snappy-card/1",
  "skill": "snappy-voice-control",
  "tier": "public",
  "origin_tier": "base",
  "purpose": "Two shipping open-source Mac agents solved voice input the hard way; this skill is",
  "verbs": [
    {
      "name": "devices",
      "args": [],
      "effect": "read",
      "firstCall": "npx tsx ~/.claude/skills/snappy-voice-control/api.ts devices"
    },
    {
      "name": "permissions",
      "args": [],
      "effect": "read",
      "firstCall": "npx tsx ~/.claude/skills/snappy-voice-control/api.ts permissions"
    },
    {
      "name": "pick",
      "args": [],
      "effect": "read",
      "firstCall": "npx tsx ~/.claude/skills/snappy-voice-control/api.ts pick"
    },
    {
      "name": "record",
      "args": [
        "secs?",
        "out-path?"
      ],
      "effect": "write-reversible",
      "firstCall": "npx tsx ~/.claude/skills/snappy-voice-control/api.ts record"
    },
    {
      "name": "stream-url",
      "args": [],
      "effect": "write-reversible",
      "firstCall": "npx tsx ~/.claude/skills/snappy-voice-control/api.ts stream-url"
    },
    {
      "name": "transcribe",
      "args": [
        "audio-file?"
      ],
      "effect": "write-reversible",
      "firstCall": "npx tsx ~/.claude/skills/snappy-voice-control/api.ts transcribe"
    }
  ],
  "faces": [],
  "agents": [],
  "uses": [
    "snappy-ax",
    "snappy-agent-host",
    "snappy-video",
    "snappy-cleanshot",
    "snappy-faces"
  ],
  "used_by": [
    "snappy-ax"
  ],
  "checks": {
    "pass": 37,
    "fail": 8,
    "defer": 16,
    "line": "37 of 45 checks pass",
    "failing": [
      {
        "id": 4,
        "rule": "Near-neighbour descriptions cross-reference each other",
        "says": "near neighbours not named: snappy-client-feisst, snappy-runner, snappy-specwatch"
      },
      {
        "id": 8,
        "rule": "Skill body and reference graph stay within disclosure budgets",
        "says": "296 lines; ~6759 tokens"
      },
      {
        "id": 9,
        "rule": "Time-sensitive prose is isolated under Old patterns",
        "says": "1 time-sensitive instruction line(s) outside Old patterns"
      },
      {
        "id": 10,
        "rule": "One term names each concept",
        "says": "mixed synonym sets: endpoint/url/route/path"
      },
      {
        "id": 11,
        "rule": "Each task presents one default, not a menu",
        "says": "1 line(s) present three-way alternative menus"
      },
      {
        "id": 40,
        "rule": "Metadata, skill body, and resources follow three-level budgets",
        "says": "metadata ~251 tokens; body ~6759 tokens"
      },
      {
        "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/extract-agent-hotword.md",
    "references/extract-fazm-voice.md",
    "refusals.test.ts"
  ],
  "total_size": 196931,
  "checksum": "sha256:f23132f2f1083dd2d98dd628a6855b2e490c3c5211f6ee8be6d6b4c1ccccad7c",
  "built_at": "2026-09-09T22:11:23.174Z",
  "openapi": {
    "openapi": "3.1.0",
    "info": {
      "title": "snappy-voice-control",
      "version": "0.0.0",
      "description": "Voice control on macOS, extracted from two shipping open-source agents (fazm by mediar-ai; Agent! by AgentiLoop): mic capture without AVAudioEngine's Bluetooth trap, push-to-talk on a bare modifier key, an 'Agent!' hotword over SFSpeechRecognizer partials, Deepgram nova-3 batch vs streaming, turn-taking, the floating bar, and the permission/TCC lies that break all of it. Use when Robert says: /snappy-voice-control, \\\"add voice to the app\\\", \\\"push to talk\\\", \\\"hold a key to talk\\\", \\\"wake word\\\", \\\"say agent and it runs\\\", \\\"the mic isn't working\\\", \\\"AirPods make it sound bad\\\", \\\"why did it stop listening\\\", \\\"transcribe this with deepgram\\\", \\\"record from the mic\\\", \\\"which mic is the default\\\". NOT the accessibility tree / clicking UI (see snappy-ax). NOT hosting Claude Code / Codex inside the app (see snappy-agent-host). NOT Whisper video captioning (see snappy-video). Triggers on: voice, push-to-talk, hotword, wake word, microphone, Deepgram, transcribe, AirPods, SFSpeechRecognizer."
    },
    "x-snappy-transport": "cli",
    "servers": [
      {
        "url": "npx tsx ~/.claude/skills/snappy-voice-control/api.ts",
        "description": "The hand itself. Every path is a verb word, every query or body key an argument."
      }
    ],
    "paths": {
      "/devices": {
        "get": {
          "operationId": "snappy_voice_control_devices",
          "summary": "snappy-voice-control devices",
          "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`."
            }
          }
        }
      },
      "/permissions": {
        "get": {
          "operationId": "snappy_voice_control_permissions",
          "summary": "snappy-voice-control permissions",
          "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`."
            }
          }
        }
      },
      "/pick": {
        "get": {
          "operationId": "snappy_voice_control_pick",
          "summary": "snappy-voice-control pick",
          "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`."
            }
          }
        }
      },
      "/record": {
        "post": {
          "operationId": "snappy_voice_control_record",
          "summary": "snappy-voice-control record",
          "x-snappy-effect": "write-reversible",
          "x-snappy-annotations": {
            "readOnlyHint": false,
            "destructiveHint": false,
            "idempotentHint": false,
            "openWorldHint": true
          },
          "requestBody": {
            "required": false,
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "secs": {
                      "type": "string",
                      "description": "Recording length in seconds",
                      "x-snappy-position": 0
                    },
                    "out-path": {
                      "type": "string",
                      "description": "Path the recording is written to",
                      "x-snappy-position": 1
                    }
                  }
                }
              }
            }
          },
          "responses": {
            "200": {
              "description": "The verb's own answer, as printed by `--json`."
            }
          }
        }
      },
      "/stream-url": {
        "post": {
          "operationId": "snappy_voice_control_stream_url",
          "summary": "snappy-voice-control stream-url",
          "x-snappy-effect": "write-reversible",
          "x-snappy-annotations": {
            "readOnlyHint": false,
            "destructiveHint": false,
            "idempotentHint": false,
            "openWorldHint": true
          },
          "requestBody": {
            "required": false,
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {}
                }
              }
            }
          },
          "responses": {
            "200": {
              "description": "The verb's own answer, as printed by `--json`."
            }
          }
        }
      },
      "/transcribe": {
        "post": {
          "operationId": "snappy_voice_control_transcribe",
          "summary": "snappy-voice-control transcribe",
          "x-snappy-effect": "write-reversible",
          "x-snappy-annotations": {
            "readOnlyHint": false,
            "destructiveHint": false,
            "idempotentHint": false,
            "openWorldHint": true
          },
          "requestBody": {
            "required": false,
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "audio-file": {
                      "type": "string",
                      "description": "Path to the audio file to transcribe",
                      "x-snappy-position": 0
                    }
                  }
                }
              }
            }
          },
          "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": [
      "DEEPGRAM_API_KEY"
    ]
  }
}