{
  "schema": "snappy-card/1",
  "skill": "snappy-artifact-loop",
  "tier": "public",
  "origin_tier": "base",
  "purpose": "**A published Artifact is an input device, and you are its backend.** Do not",
  "verbs": [
    {
      "name": "channels",
      "args": [],
      "effect": "read",
      "firstCall": "npx tsx ~/.claude/skills/snappy-artifact-loop/api.ts channels"
    },
    {
      "name": "choose",
      "args": [
        "opts-json?"
      ],
      "effect": "read",
      "firstCall": "npx tsx ~/.claude/skills/snappy-artifact-loop/api.ts choose"
    },
    {
      "name": "envelope",
      "args": [
        "kind",
        "payload-json",
        "page-key?"
      ],
      "effect": "read",
      "firstCall": "npx tsx ~/.claude/skills/snappy-artifact-loop/api.ts envelope <kind> '[\"<payload>\"]'"
    },
    {
      "name": "kit",
      "args": [
        "kind",
        "page-key"
      ],
      "effect": "read",
      "firstCall": "npx tsx ~/.claude/skills/snappy-artifact-loop/api.ts kit <kind> <page-key>"
    },
    {
      "name": "parse",
      "args": [
        "text?"
      ],
      "effect": "read",
      "firstCall": "npx tsx ~/.claude/skills/snappy-artifact-loop/api.ts parse"
    }
  ],
  "faces": [],
  "agents": [],
  "uses": [],
  "used_by": [],
  "checks": {
    "pass": 38,
    "fail": 10,
    "defer": 13,
    "line": "38 of 48 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, snappy-whatsapp"
      },
      {
        "id": 5,
        "rule": "Description is valid, third-person, and says what plus when",
        "says": "first/second person"
      },
      {
        "id": 8,
        "rule": "Skill body and reference graph stay within disclosure budgets",
        "says": "848 lines; ~10901 tokens"
      },
      {
        "id": 9,
        "rule": "Time-sensitive prose is isolated under Old patterns",
        "says": "4 time-sensitive instruction line(s) outside Old patterns"
      },
      {
        "id": 10,
        "rule": "One term names each concept",
        "says": "mixed synonym sets: endpoint/url/route/path, field/box/element"
      },
      {
        "id": 31,
        "rule": "Refusals have outcome, code, message, and fix",
        "says": "refusals schema-checked for outcome/code/message/fix"
      },
      {
        "id": 32,
        "rule": "Refusals name a literal from the valid domain",
        "says": "refusals checked against contract literals"
      },
      {
        "id": 40,
        "rule": "Metadata, skill body, and resources follow three-level budgets",
        "says": "metadata ~234 tokens; body ~10901 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",
    "bridge.py",
    "contract.test.ts"
  ],
  "total_size": 85265,
  "checksum": "sha256:2d4fa25d388113f150088887aa2cd7250e3c48a3ef518360fa1a050f153aef0d",
  "built_at": "2026-09-09T22:08:08.773Z",
  "openapi": {
    "openapi": "3.1.0",
    "info": {
      "title": "snappy-artifact-loop",
      "version": "0.0.0",
      "description": "Build published Artifacts as I/O devices where the AGENT is the backend, not as static output documents. Covers the six round-trip channels (clipboard envelope, artifact comments, self-publish + WebFetch, sample, db, room), the decision table for picking one, the copy-back envelope contract that makes a paste machine-parseable, and what is verified vs unverified on each channel. Use when asked for: an artifact, an HTML page or tool, \"agent as backend\", a page that talks back, a review or approval surface, \"no dedicated backend\", a monitor that updates a page, an artifact loop, a round-trip page. NOT local file:// review pages with a copy-all feedback bar (see snappy-review-pages). NOT visual design of the page (see artifact-design). Triggers: artifact loop, agent as backend, round-trip page, copy back to claude, make an artifact, page that talks back, no dedicated backend, snappy-artifact-loop, artifact channels, envelope."
    },
    "x-snappy-transport": "cli",
    "servers": [
      {
        "url": "npx tsx ~/.claude/skills/snappy-artifact-loop/api.ts",
        "description": "The hand itself. Every path is a verb word, every query or body key an argument."
      }
    ],
    "paths": {
      "/channels": {
        "get": {
          "operationId": "snappy_artifact_loop_channels",
          "summary": "snappy-artifact-loop channels",
          "x-snappy-effect": "read",
          "x-snappy-annotations": {
            "readOnlyHint": true,
            "destructiveHint": false,
            "idempotentHint": false,
            "openWorldHint": false
          },
          "parameters": [],
          "responses": {
            "200": {
              "description": "The verb's own answer, as printed by `--json`."
            }
          }
        }
      },
      "/choose": {
        "get": {
          "operationId": "snappy_artifact_loop_choose",
          "summary": "snappy-artifact-loop choose",
          "x-snappy-effect": "read",
          "x-snappy-annotations": {
            "readOnlyHint": true,
            "destructiveHint": false,
            "idempotentHint": false,
            "openWorldHint": false
          },
          "parameters": [
            {
              "name": "opts-json",
              "in": "query",
              "required": false,
              "schema": {
                "type": "string",
                "description": "JSON object of channel options to choose a rendition from",
                "x-snappy-position": 0
              }
            }
          ],
          "responses": {
            "200": {
              "description": "The verb's own answer, as printed by `--json`."
            }
          }
        }
      },
      "/envelope": {
        "get": {
          "operationId": "snappy_artifact_loop_envelope",
          "summary": "snappy-artifact-loop envelope",
          "x-snappy-effect": "read",
          "x-snappy-annotations": {
            "readOnlyHint": true,
            "destructiveHint": false,
            "idempotentHint": false,
            "openWorldHint": false
          },
          "parameters": [
            {
              "name": "kind",
              "in": "query",
              "required": true,
              "schema": {
                "type": "string",
                "description": "Artifact kind the envelope wraps",
                "x-snappy-position": 0
              }
            },
            {
              "name": "payload-json",
              "in": "query",
              "required": true,
              "schema": {
                "type": "string",
                "description": "JSON payload placed inside the envelope",
                "x-snappy-position": 1
              }
            },
            {
              "name": "page-key",
              "in": "query",
              "required": false,
              "schema": {
                "type": "string",
                "description": "Page the envelope belongs to",
                "x-snappy-position": 2
              }
            }
          ],
          "responses": {
            "200": {
              "description": "The verb's own answer, as printed by `--json`."
            }
          }
        }
      },
      "/kit": {
        "get": {
          "operationId": "snappy_artifact_loop_kit",
          "summary": "snappy-artifact-loop kit",
          "x-snappy-effect": "read",
          "x-snappy-annotations": {
            "readOnlyHint": true,
            "destructiveHint": false,
            "idempotentHint": false,
            "openWorldHint": false
          },
          "parameters": [
            {
              "name": "kind",
              "in": "query",
              "required": true,
              "schema": {
                "type": "string",
                "description": "Artifact kind whose kit is returned",
                "x-snappy-position": 0
              }
            },
            {
              "name": "page-key",
              "in": "query",
              "required": true,
              "schema": {
                "type": "string",
                "description": "Page the kit is built for",
                "x-snappy-position": 1
              }
            }
          ],
          "responses": {
            "200": {
              "description": "The verb's own answer, as printed by `--json`."
            }
          }
        }
      },
      "/parse": {
        "get": {
          "operationId": "snappy_artifact_loop_parse",
          "summary": "snappy-artifact-loop parse",
          "x-snappy-effect": "read",
          "x-snappy-annotations": {
            "readOnlyHint": true,
            "destructiveHint": false,
            "idempotentHint": false,
            "openWorldHint": false
          },
          "parameters": [
            {
              "name": "text",
              "in": "query",
              "required": false,
              "schema": {
                "type": "string",
                "description": "Text to parse an envelope out of; omit to read stdin",
                "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"
            }
          }
        }
      }
    }
  }
}