{"slug": "i-vibe-coded-a-cryptid-reporting-station-on-sanity-and-the-workflow-rejects", "title": "I Vibe-Coded a Cryptid-Reporting Station on Sanity (and the Workflow Rejects Bigfoot Blurs)", "summary": "A developer built Cryptid Field Station, a Sanity-based monorepo application that lets hikers report cryptid sightings and routes each report through an AI-plus-human verification workflow, with obvious fabrications auto-rejected and borderline cases queued for human review. The project uses a single transition() function for all write paths, a real-time Ranger triage app built on @sanity/client listen(), and a seeded jackalope report that admits to being taxidermy as a pipeline control sample. The build was prompted end-to-end in the agentic IDE OpenCode, with the developer noting course corrections away from the early-access @sanity/workflow-engine and @sanity/sdk-react in favor of a data-modeled workflow and a custom real-time interface.", "body_md": "*This is a submission for the [Sanity Challenge, Path Two: Vibe-Code Something Strange](https://dev.to/challenges/sanity-2026-09-16)*\n\n**Cryptid Field Station** - a field guide where hikers report cryptid sightings, an AI + human workflow verifies them, and rangers triage from a live command center.\n\n`submitted ? in-review ? verified ? published`); obvious fabrications auto-reject; everything in between waits for a human `verification` document next to the sighting - one audit trail, two authors (agent + human).\nThe control sample is my favorite part: the seed data includes a jackalope report that openly admits to being taxidermy. If the pipeline ever publishes it, the pipeline is broken. It gets rejected.\n\n`studio/` today (`npx sanity dev`); the hosted Studio URL lands here right after `sanity deploy` (custom evidence input below)\nTry it: file a sighting at `/report` (lat/lng optional but the weather check loves them), then watch it land in the Ranger Board's `submitted` lane and move through review.\n\n`web/` - Next.js 14 guide + workflow API routes (`/api/sightings`, `/transition`)` EvidenceGifInput` (paste a trail-cam video URL, get a preview + capturable 6-frame GIF-strip)`ranger/` - real-time triage app (live Sanity subscription, own UI)`workflows/sighting-review.ts` - the review process as data (stages, guards, effects)`seed/` - 7 cryptids, 12 sightings with mixed fates, idempotent importer\n**IDE:** OpenCode (agentic, autonomous) powered by Muse Spark - prompted end-to-end, no interactive Studio clicking for the build itself.\n\n**Prompts that worked:** \"scaffold a monorepo with these four folders and make every app build before touching Sanity\" (got three green builds in a row); \"every write path goes through one `transition()` function\" (kept agent + ranger honest); \"reads must work with an empty dataset\" (the baked-in field cache, which saved the demo before seeding).\n\n**Prompts that didn't:** asking for the App SDK with `@sanity/sdk-react` from memory - I couldn't pin the exact provider API without docs in hand, so I course-corrected to a real-time custom app on `@sanity/client` `listen()` with its own UI, which is what the bonus actually asks for (\"your own interface, instead of another read-only frontend\"). The workflow engine went the same way: rather than fight the early-access `@sanity/workflow-engine` setup, I modeled the process as data (`status` + `verification` docs, cookbook-mapped in `workflows/`), which runs on any plan today.\n\n**Where it got stuck:** an npm cache corruption on `esbuild` killed the Studio install (fixed with `--prefer-online` retry); the Vercel CLI hung on update-notifier checks in a non-TTY shell (fixed with `NO_UPDATE_NOTIFIER=1`); a TS slug-shape mismatch between raw seed JSON and the `Cryptid` type (fixed by mapping `slug.current` at the fallback boundary).\n\n**Past the Studio:** yes to both bonuses. The Ranger app is a custom real-time surface with live updates and approve/reject/publish actions - not Studio, not read-only. The workflow is data: the agent moves drafts forward (triage, auto-verify ?90, auto-reject ?20) and the ranger approves through identical transitions, all audit-logged side by side.\n\n`yy3ugxmv` (dataset `production`)` cryptid` (classification, danger 1-5, traits, habitat), `sighting` (cryptid ref, geopoint, evidence URL+type, workflow-owned `status`, cached weather), `expedition` (cryptid/sighting refs for joint field pushes), `credibilityScore` are `readOnly` in Studio - the workflow owns them, humans use the board; evidence type drives conditional rendering (video player vs image); the jackalope is `debunked` by design as a pipeline control.\nBuilt autonomously in OpenCode; transcript available on request. Key decision log: monorepo-first, cache-first reads, one-transition-function rule, honest 503s when the write token is absent.", "url": "https://wpnews.pro/news/i-vibe-coded-a-cryptid-reporting-station-on-sanity-and-the-workflow-rejects", "canonical_source": "https://dev.to/aniruddhaadak/i-vibe-coded-a-cryptid-reporting-station-on-sanity-and-the-workflow-rejects-bigfoot-blurs-cmc", "published_at": "2026-09-23 05:27:02+00:00", "updated_at": "2026-09-23 05:52:39.338917+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "ai-tools"], "entities": ["Sanity", "OpenCode", "Next.js", "Vercel", "Muse Spark", "@sanity/client", "@sanity/workflow-engine", "Cryptid Field Station"], "alternates": {"html": "https://wpnews.pro/news/i-vibe-coded-a-cryptid-reporting-station-on-sanity-and-the-workflow-rejects", "markdown": "https://wpnews.pro/news/i-vibe-coded-a-cryptid-reporting-station-on-sanity-and-the-workflow-rejects.md", "text": "https://wpnews.pro/news/i-vibe-coded-a-cryptid-reporting-station-on-sanity-and-the-workflow-rejects.txt", "jsonld": "https://wpnews.pro/news/i-vibe-coded-a-cryptid-reporting-station-on-sanity-and-the-workflow-rejects.jsonld"}}