The Stash protocol.

How LLMs and agentic tools read Stash captures. This page is the human-readable companion to /llms.txt — the same spec, same precedence rules, just nicer to skim.

Precedence: MCP > XMP > pixel banner. Each is a fallback for the layer above. Protocol version: stash-1.

Key takeaways

Three channels, one capture

Every Stash screenshot carries structure in three places so a capture can always be resolved — even after the user pastes it into a web chat and every byte of metadata is stripped.

ChannelSurvivesWhat it carries
Pixel banner Anything an image survives App, window title, appearance, OS version, timestamp, shortID
XMP metadata File-on-disk flows (Drive, email) Full structured payload: annotations, a11y tree summary, dev context
MCP server Local RPC (same machine) Live dossier including full a11y tree and un-summarized fields

Screenshot banner

Rendered at the bottom of every Stash screenshot in a monospace font:

📌 Claude — Settings · dark · macOS 26.4 · 2026-04-12 14:24 · #8FD26F28

When the user drew annotations, a second line appears above the pin:

user focus: blue arrow pointing · red box enclosing

The banner describes shape behavior — never the target. Resolve the target yourself using vision and/or the a11y tree.

XMP payload

On auto-save-to-desktop for developer apps, the JPEG carries an XMP payload under namespace http://stash.app/ns/1.0/. Serialized as a single JSON string under stash:payload:

{
  "protocolVersion": "stash-1",
  "source": "xmp-snapshot",
  "captureId": "8FD26F28-…",
  "mcpURI": "stash://capture/8FD26F28-…",
  "snapshotTimestamp": "2026-04-12T14:24:00Z",
  "appName": "Cursor",
  "bundleID": "com.todesktop.230313mzl4w4u92",
  "windowTitle": "ContextBannerRenderer.swift",
  "appearance": "dark",
  "osVersion": "macOS 26.4",
  "userFocus": [
    { "type": "arrow", "color": "BA0C2F", "behavior": "pointing",
      "from": [120, 340], "to": [420, 300] }
  ],
  "a11yTreeSummary": { /* trimmed: top 3 levels + labelled controls */ },
  "devContext": {
    "activeFilePath": "/Users/x/proj/Foo.swift",
    "selectedText": "let appearance = …",
    "gitBranch": "main"
  }
}

Also tagged with IPTC 2025.1 Iptc4xmpExt:AISystemUsed = "Stash" so conformant tooling can detect AI-assisted captures. Filename convention on save-to-desktop: Stash-YYYY-MM-DD-HHmmss-{shortID}.jpg.

Video bundles

Produced by the Stash screen recorder. A self-describing folder, indexable as one unit:

Recordings/<uuid>/
├── report.md           ← YAML frontmatter + markdown timeline
├── frame_tags.json     ← { "frames": [ … ] } — per-frame app/window/tag
├── llms.txt            ← offline self-description
├── frame_NN.jpg        ← 1-indexed, zero-padded; hard-capped at 30 per
│                         recording. Start + end bookends always kept;
│                         remaining budget sampled uniformly from
│                         interaction frames, then ambient. Read in
│                         numeric order via frame_tags.json.
├── audio.m4a           ← extracted audio when present
└── video.mp4           ← original; generally skip

The report.md opens with machine-readable YAML frontmatter:

---
protocol: stash-1
bundleVersion: 2
captureId: <UUID>
duration: 42.30
frameCount: 12
hasAudio: true
primaryApp: Cursor
mcpURI: stash://bundle/<UUID>
---

MCP server

Stash ships a local Model Context Protocol server on a UNIX domain socket at ~/Library/Application Support/Stash/mcp.sock — line-delimited JSON-RPC 2.0. Local-only by design; the socket is not exposed to the network.

Transport

Stdio MCP clients (Claude Code, Cursor, Codex CLI, etc.) connect via a small bridge binary at ~/.local/bin/stash-mcp that relays stdin/stdout to the socket. The one-line installer at yourstash.ai/claude compiles it, signs it, and registers it with every Claude client it finds.

Manual registration by client:

Peer auth

Stash reads the peer's codesign team identifier on connect and silently rejects unknown signers. Built-in allowlist: Anthropic (58LP8PCM82) and Stash itself (VJMJQKCRMC). Extend via Stash → Settings → Privacy → Additional trusted team IDs, or toggle Allow unsigned MCP clients for local experiments.

Tools

ToolPurpose
stash.get_capture(id)Full dossier for a screenshot or video capture
stash.get_bundle(id)Video bundle: report.md, enriched frame_tags, absolute file paths
stash.list_recent(n)Paste-flow fallback; compact summaries newest-first
stash.search(query)Substring match over app / window / text / URL
stash.render_plain(id)Raw JPEG bytes, no banner, no XMP (for evals)

All tools return the MCP-standard {content: [{type: "text", text: "<json>"}]} envelope. render_plain returns {type: "image", data: "<base64>", mimeType: "image/jpeg"}.

Privacy model

Versioning

stash-1 is stable. Additive changes (new fields, new tools) land as v1.1, v1.2 and do not break v1 readers. A breaking change bumps to stash-2. Prefer live MCP data over a frozen XMP snapshot when both are available.

The machine-readable version of this page lives at yourstash.ai/llms.txt. Point your agent's config there for a one-shot sync; it's the same spec as above, optimized for plain-text consumption.

Frequently asked questions

What is the stash-1 protocol?

The stash-1 protocol is Stash's specification for how LLMs and agentic tools read Stash captures across three channels: the pixel banner rendered into every screenshot, XMP metadata embedded in the saved JPEG, and a local Model Context Protocol (MCP) server. Each channel is a fallback for the layer above.

Which channel is most authoritative — banner, XMP, or MCP?

The MCP server is most authoritative when the original Mac is reachable, because it carries the full live dossier including the un-summarized accessibility tree. XMP is next — it survives file-on-disk flows like email and Drive. The pixel banner is the last-resort channel that survives anything an image survives, including pasted-into-chat captures where every byte of metadata has been stripped.

Can I read Stash captures from a remote machine?

No. The MCP server binds to a UNIX domain socket under the user account and is not exposed to the network by design. To read captures remotely, agents must rely on the XMP payload embedded in the file or the pixel banner.

How does Stash authenticate MCP clients?

Stash reads the connecting peer's codesign team identifier on connect and silently rejects unknown signers. The built-in allowlist trusts Anthropic (team 58LP8PCM82) and Stash itself (team VJMJQKCRMC). Additional team IDs can be added via Settings → Privacy, or unsigned clients can be allowed for local experimentation.

Are Stash video bundles indexable by AI tools?

Yes. Each bundle is a self-describing folder containing report.md with YAML frontmatter, frame_tags.json with per-frame app and window metadata, an offline llms.txt, sampled JPEG frames (capped at 30 per recording), and extracted audio. Agents read it as a single unit via stash.get_bundle().

Will the stash-1 protocol ever break?

No. The stash-1 protocol is stable. Additive changes — new fields, new tools — land as v1.1, v1.2 and do not break existing v1 readers. A breaking change would bump to stash-2.

Related reading