{"slug": "it-s-got-what-content-craves-sanity-built-for-the-people-of-idiocracy", "title": "It's Got What Content Craves: Sanity, Built for the People of Idiocracy", "summary": "A developer built a Sanity-based Department of Agriculture simulation inspired by Idiocracy, in which a Claude agent drafts a proposal to water crops, a human Cabinet approves it through a picture-button Studio, and Sanity Workflows executes the watering and harvest. The project, built in a single Claude Code session, passed 27 of 27 timed edits across three interfaces and uses two Studio workspaces sharing one schema over a single dataset.", "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*This article provides a step by step build of a **Sanity** project for the Department of Agriculture from Idiocracy, where every field is irrigated with Brawndo. An agent proposes watering the crops, a human Cabinet approves in a picture-button Studio, and **Sanity Workflows** waters and harvests the fields. A stopwatch then times the same edits in three interfaces.*\n\n[github.com/xbill9/devto-sanity](https://github.com/xbill9/devto-sanity)\n\n| Project | Sanity `ukyhb6bu` , dataset`production` (public read), Growth trial | \n| Studio | Sanity Studio 6, two workspaces over one schema: **Kiosk** and**Stock** | \n| Workflow | `joes-plan` v1,`@sanity/workflow-*` 0.33.0 (early access) | \n| Front end | Next.js 16 + `next-sanity` live content, on Cloud Run | \n| Dashboard app | App SDK **Cabinet Room** | \n| Agent | Claude ( `claude-opus-5` ) +`@sanity/workflow-mcp` | \n| Result | agent → Cabinet → watering → **harvest** on the live project;**27 of 27** timed edits correct | \n\nIn Idiocracy the crops are dying because every field is watered with Brawndo. It's got electrolytes. Joe's plan is to water them. With water. Like from the toilet.\n\nThis is that Department of Agriculture, run on Sanity. The Secretary of the Interior is an **agent**. It drafts a proposal to water the fields and submits it. The **Cabinet**, a person, approves or rejects it. Citizens vote on a public scoreboard. An approved plan waters the fields, they sprout, and a few minutes later they are harvested. A rejected plan leaves a dust bowl.\n\nThe one pitch for a CMS that holds up is that people who can't use git can use a data store. So the editing Studio is a kiosk of giant picture buttons, like the hospital in the film.\n\n| Surface | Built with | Who uses it | \n|---|---|---|\n| **The Kiosk** | Studio with custom picture-button inputs + the Workflows plugin | the Cabinet | \n| **Joe's Plan** | Sanity Workflows | the agent, the Cabinet, the runtime | \n| **brawndo.gov** | Next.js + `next-sanity` | citizens | \n| **The Cabinet Room** | App SDK dashboard app | the Cabinet | \n\n**brawndo.gov:** [brawndo-gov-289270257791.us-central1.run.app](https://brawndo-gov-289270257791.us-central1.run.app) — vote on a field; voting again replaces your vote.\n\nThe Kiosk is hosted at `brawndo-agriculture.sanity.studio` and signs in through the Sanity Dashboard.\n\n[https://github.com/xbill9/devto-sanity](https://github.com/xbill9/devto-sanity)\n\n`make check` runs the offline suite. The README has the go-live runbook.\n\nThe whole project was built in one Claude Code session, from an empty directory to a harvested field.\n\nWith what Sanity sells. A schema'd JSON store with a query language is common. Three things in Sanity's docs are harder to find elsewhere:\n\nA Path Two app built around the second one is the right Brawndo.\n\n`npx sanity new` creates one with no account and a 72-hour claim link`source ./env.sh` in the repository root)\nThe schema is defined once and built twice. `buildSchema({kiosk: true})` swaps a picture-button input into every enumerated field. `buildSchema({kiosk: false})` keeps Sanity's defaults. Two Studio workspaces share one dataset, so the stock Studio is the same data without the Brawndo.\n\nA proposal has **no status field**. Its stage lives in its workflow instance, which is itself a Sanity document, so there is one source of truth for where a plan stands.\n\n```\npetition ──submit──▶ cabinet ──approve──▶ watering ──▶ growing ──(harvestAt)──▶ harvest\n                        └──reject──▶ dust-bowl\n```\n\nThe definition runs in Sanity's in-memory test bench before it is deployed:\n\n```\n ✓ definitions/joes-plan.test.ts (8 tests)\n      Tests  8 passed (8)\n```\n\nThe tests prove the Secretary cannot approve, a rejection ends in the dust bowl, failed watering ends in the dust bowl, and harvest waits for `harvestAt`.\n\n🔎 Tip: an effect handler's `outputs` land in `$effects['<effect>']`. To write a workflow field, return `ops` with an explicit `target.scope`:\n\n```\nreturn {\n  outputs: {harvestAt},\n  ops: [{type: 'field.set', target: {scope: 'workflow', field: 'harvestAt'}, value: {type: 'literal', value: harvestAt}}],\n}\n```\n\nSanity's Workflows docs say every check the engine makes is advisory. Role checks, guards and action filters shape the interface; the Content Lake enforces only dataset access control. So the Cabinet's power depends on a role the agent's token lacks.\n\nThe Growth trial has the eight built-in roles and no custom ones:\n\n```\nError: workflow.deployDefinitions: unknown project roles for project \"ukyhb6bu\":\n  - joes-plan: generated role condition references unknown role \"secretary\"\n  - joes-plan: generated role condition references unknown role \"cabinet\"\n```\n\nThe definition therefore reads its role names from the environment and deploys with `administrator` for the Cabinet and `editor` for the Secretary. A robot token cannot hold `administrator`:\n\n``` bash\n$ sanity tokens add brawndo-e2e-cabinet --role administrator ...\nError: Invalid role \"administrator\". Available roles: editor, developer,\ncontributor, access-manager, blueprints-deployer, deploy-studio, viewer\n```\n\n⚠️ **The Cabinet can only be a person, and it has no power.** The agent's `editor` token can write the fields directly. The Cabinet has a seat, a button, and an advisory vote. That's the movie.\n\nThe agent submits, the Cabinet approves in the Kiosk, and the runtime waters and harvests. Live, on the project:\n\n```\n16:46:07  agent submitted cabinet\n16:46:08  agent approve rejected (engine verdict, advisory) ActionDisabledError\n16:46:59  drainer watered { stage: 'growing', harvestAt: '2026-09-18T16:47:00.255Z' }\n16:47:16  final stage harvest\n16:47:16  fields after harvest [ { growth: 'crop', irrigation: 'water', number: 7 },\n                                 { growth: 'crop', irrigation: 'water', number: 9 } ]\n```\n\nBetween the second and third lines, a person clicked **Approve (water)** in the Kiosk.\n\n🔎 Tip: Workflows is a library. Nothing moves unless code calls it, so something has to call `tick` after `harvestAt` passes and drain queued effects. Here that is `npm run runtime:watch`; in production it is a pair of Sanity Functions.\n\nEvery tally on brawndo.gov is a GROQ `count()` computed by the Content Lake:\n\n```\ncount(*[_type == \"vote\" && field._ref == ^._id && choice == \"water\"])\n```\n\nNothing is summed in React, and the agent never counts rows. Its `field_report` tool returns the engine's numbers with the filter it ran.\n\nOne vote per citizen per field holds by construction: a vote's `_id` is built from both, so voting again replaces the vote. Three votes in, two votes out, read back anonymously:\n\n``` php\nvote field-07 -> HTTP 200\nvote field-07 -> HTTP 200\nvote field-03 -> HTTP 200\nanonymous public read: {'anonCitizens': 1, 'f7water': 1, 'votes': 2}\n```\n\n🔎 Tip: a document `_id` containing a dot is never served anonymously from a public dataset. Vote ids use hyphens. Workflow instance ids contain dots (`dev.wf-instance.…`), so brawndo.gov reads the docket on the server with a token.\n\n🔎 Tip: on a service that scales to zero, a prerendered page shows build-time data after every cold start. The scoreboard renders per request, and `<SanityLive>` keeps an open page current.\n\nThe question behind the Kiosk: can idiots use a data store? The protocol times three tasks in three interfaces, three runs each:\n\nThe interfaces are the Kiosk, the stock Studio, and the same data as markdown files edited in GitHub's web editor.\n\nA script starts the clock when the task is issued and stops it when the participant signals done. Another script checks the result against the dataset or the repository and records whether it is correct. Every number below comes from `analyze.py` reading the raw CSV, which is published in the repository.\n\nThe first participant is an agent: Claude, driving Chrome through the Claude in Chrome extension.\n\nMedian seconds over three runs, participant A1 (the agent):\n\n| Surface | Water a field | Add a citizen | Amend a proposal | Correct | \n|---|---|---|---|---|\n| Stock Studio | 🥇 24.8 s | 🥇 16.8 s | 🥇 37.6 s | 9/9 | \n| Kiosk (picture buttons) | 🥈 26.4 s | 🥈 25.6 s | 🥈 41.4 s | 9/9 | \n| Markdown on GitHub | 🥉 37.2 s | 🥉 41.2 s | 🥉 46.2 s | 9/9 | \n\nThe stock Studio is fastest for the agent on every task, and GitHub is slowest on every task. The agent reads the accessibility tree, where a giant picture of a water glass and a small radio button carry the same label.\n\nBoth Studios beat editing files. Adding a citizen in GitHub means creating a file, naming it, and typing the frontmatter by hand. Amending a proposal means editing an array inside YAML without breaking it.\n\nFor an agent, the stock Studio. For the people of Idiocracy, the Kiosk, and that is the next measurement: the same protocol with a person who has never used git.\n\n`ukyhb6bu`, dataset `production` (public read)`joes-plan` v1, tag `dev`\n`field`, `citizen`, `proposal`, `vote`\nThe goal of this article was to build the Department of Agriculture from Idiocracy on Sanity and time whether its interface for non-programmers makes editing faster. The key to the solution was Sanity Workflows, where an agent and a person move the same document through the same transitions. The results were:\n\n`administrator`\n`editor` token\nScope: one Sanity project on the Growth trial, `@sanity/workflow-*` 0.33.0, one participant (the agent) with three runs per task per interface in the order Kiosk, stock Studio, GitHub. The agent's times include the model's time to decide each action, and the Kiosk ran first, so it carries the learning curve.\n\nThe strategy for using Sanity Workflows for an agent-and-person approval process was validated with an incremental step by step approach.", "url": "https://wpnews.pro/news/it-s-got-what-content-craves-sanity-built-for-the-people-of-idiocracy", "canonical_source": "https://dev.to/xbill/its-got-what-content-craves-sanity-built-for-the-people-of-idiocracy-4k84", "published_at": "2026-09-18 21:36:10+00:00", "updated_at": "2026-09-18 21:52:52.281509+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "developer-tools", "agent-protocols"], "entities": ["Sanity", "Claude", "Next.js", "Google Cloud Run", "GitHub", "Idiocracy", "Brawndo"], "alternates": {"html": "https://wpnews.pro/news/it-s-got-what-content-craves-sanity-built-for-the-people-of-idiocracy", "markdown": "https://wpnews.pro/news/it-s-got-what-content-craves-sanity-built-for-the-people-of-idiocracy.md", "text": "https://wpnews.pro/news/it-s-got-what-content-craves-sanity-built-for-the-people-of-idiocracy.txt", "jsonld": "https://wpnews.pro/news/it-s-got-what-content-craves-sanity-built-for-the-people-of-idiocracy.jsonld"}}