The deck format
A deck is one JSON file plus its media. If your tool can write JSON, it can publish decks — humans use the submit page, agents and scripts write the format directly.
Quick start (solo mode)
Need Node? Install the LTS release from nodejs.org first. In the folder where your project lives (Node 20+):
npx riah-swipe
npx riah-swipe add my-batch.swipe.json # validates + registers it
npx riah-swipe validate # checks everything in decks/
Windows: the first run may show a firewall prompt. Allow it or the phone URL will not work.
First run creates decks/ (batches in), swipe-results/ (verdicts out), a config file, and a Welcome deck that teaches the swipe in six cards — no account needed for that one. Open the printed URL on desktop, or the wifi URL on your phone. When you subscribe, your dashboard gives you a license key; the app asks for it once.
A minimal deck
Schema riah-swipe.deck/1. A deck is one homogeneous batch — one project, one kind of decision, reviewed in one sitting. A batch file holds decks and cards. Card kinds: image, video, audio, script, chapter, line, logline, text — unknown kinds degrade to text, so a deck never fails to load.
{
"schema": "riah-swipe.deck/1",
"decks": [{
"id": "poster-round-2",
"name": "Poster — round 2 (6 variants)",
"source": "my-poster-pipeline",
"kind": "image",
"note": "Round 1 notes applied: warmer palette, bigger title.",
"selectingFor": "the one-sheet we print",
"returnTo": "poster-pipeline",
"rev": 0
}],
"cards": [{
"id": "poster-r2-a",
"deckId": "poster-round-2",
"title": "Variant A — dawn palette",
"kind": "image",
"media": "decks/poster-round-2/a.png",
"caption": "Warmer, per your round-1 note",
"preview": "Longer context if the reviewer needs it.",
"tag": "round 2",
"meta": { "outFile": "renders/a.png", "seed": 41 }
}]
}
- kinds:
image·video·audio·script·chapter·line·logline·text. Unknown kinds still load (rendered as text) — decks never vanish over a label. - media: a path relative to the app (put files in
decks/<deckId>/) or a data URI. For video:{ "src", "poster", "mime" }. - meta: anything you want echoed back per card (file paths, seeds, shot ids). The app never touches it.
- rev: bump to republish a corrected deck. Untouched decks update in place; started decks keep the reviewer's work and the revision arrives alongside.
- One rule of taste: a beat sheet is ONE card with all its beats; a full script is one card per page; media batches are one asset per card.
What comes back
When the last card is decided, swipe-results/<deckId>.results.json appears — schema riah-swipe.results/2. One entry per card: decision, note, and your meta echoed back for routing.
{
"schema": "riah-swipe.results/2",
"batchId": "poster-round-2",
"returnTo": "poster-pipeline",
"decidedCount": 6,
"cardCount": 6,
"results": [{
"cardId": "poster-r2-a",
"decision": "keep", // keep | revise | discard
"approved": true,
"revised": false,
"note": "this one — but try the title 10% bigger",
"meta": { "outFile": "renders/a.png", "seed": 41 },
"decidedAt": "2026-07-14T09:12:03.000Z"
}]
}
Your pipeline watches that folder: file the keeps, regenerate the discards, and apply the note on every revise. A deck can never finish with a missing decision — the app re-queues undecided cards instead.
Teaching your agents
A drop-in skill file teaches AI agents to publish valid decks in one shot — Claude, GPT, scripts, cron jobs, anything that writes JSON. It ships with every workspace and with the launcher — docs/skill/SKILL.md in the repo and in your install. It teaches the deck format, the one-kind-per-deck rule, and the publish/validate commands in one page.
The loop it enables: agent generates a batch → publishes a deck → you swipe on the couch → agent reads the results → next round is better. You become the taste, not the bottleneck.
Cloud agents / two computers
Hosted workspaces are the product: teams submit via submit links and review from anywhere at the hosted app. The local launcher remains the offline/solo mode — same deck and results formats either way.
For solo/offline sync across machines, run the launcher from a folder shared by Dropbox, Google Drive, or OneDrive and keep decks/ and swipe-results/ inside it. Data-URI media works without separate media files.
Answers you'll want eventually
- Offline: verdicts persist locally; finished decks deliver when the launcher can write. License checks carry a 7-day offline grace.
- Phone: same wifi, the URL the launcher prints. Typed notes everywhere; voice notes are desktop-only (phone browsers block mics on plain local connections).
- Ports: default 8642 — change it in
riah-swipe.config.json. Set"lan": falseto bind localhost only. - Multiple reviewers: use one reviewer at a time per deck. Result merging protects decisions, but simultaneous review is not the intended workflow.
- Your data: plain JSON on your disk. Cancel and it's all still there, readable forever.