{
 "note": "Desktop build recipes, ordered by ease x safety. The ids match the section ids in data/context/desktop-surfaces.md (A1-A3, B1-B6, and the Tier C refusals), and integrity.test.mjs asserts they still agree — so the catalogue the generator picks from and the catalogue the model reads cannot diverge. Each recipe also carries a `harms` array, derived from selection.byHarm so the resources page can file it under the problem it addresses rather than in a separate list. Where a recipe appears in no byHarm list, harmsDerivedFrom says so and the assignment comes from its mechanism — B6 is the only one.",
 "selection": {
  "note": "How the generator picks. Harm first, then the user's stated preference from the build question, then the failure history. A recipe is only ever offered on a platform it actually works on.",
  "byHarm": {
   "exposure": [
    "A1",
    "A2",
    "B2"
   ],
   "time_displacement": [
    "A2",
    "B1",
    "B3",
    "B2",
    "B5"
   ],
   "interference": [
    "A3",
    "B4",
    "B3",
    "A2"
   ],
   "boundary": [
    "B3",
    "B2",
    "B1",
    "B4"
   ]
  },
  "byPreference": {
   "extension": [
    "A2",
    "A1",
    "A3"
   ],
   "config": [
    "A1",
    "B2",
    "B1",
    "B4"
   ],
   "nopref": [],
   "existing": []
  },
  "byFailure": {
   "bypassed": [
    "B5",
    "B1"
   ],
   "nagged": [
    "A1",
    "B4",
    "B3"
   ],
   "attenuated": [
    "B3",
    "B2"
   ],
   "uninstalled": [
    "A1",
    "B2",
    "B3"
   ]
  },
  "failureNote": {
   "bypassed": "You said you found ways around a limit before, so the cost-of-exit wrapper and the hosts-file block are moved up: both are harder to undo on impulse than an app you can quit.",
   "nagged": "You said prompts stopped registering, so the recipes that prompt you have been moved down in favour of ones that change the environment and then say nothing.",
   "attenuated": "You said something worked and then stopped, so the scheduled and passive recipes are moved up — they do not depend on your continuing to notice them.",
   "uninstalled": "You said you uninstalled something before, so the recipes that need no ongoing cooperation are moved up."
  }
 },
 "recipes": [
  {
   "id": "A1",
   "name": "Filter-rule or stylesheet snippet",
   "tools": "uBlock Origin, or Stylus",
   "mechanism": "exposure_limitation",
   "mechanismProse": "Removes a specific element from a specific site — a feed, a recommendation rail, a counter — and leaves the rest of the site working.",
   "setup": "Paste a rule into an extension you already have.",
   "platforms": [
    "macos",
    "windows",
    "linux"
   ],
   "securityProfile": "Nil risk. Declarative CSS or filter syntax; no code executes and nothing can make a network request. This is the safest thing on this site.",
   "effort": "minutes",
   "writesCode": false,
   "surfaceSpecific": true,
   "why": "If the problem is one identifiable thing on one identifiable page, this is the whole answer, and everything below it is more machinery than the problem needs.",
   "harmsDerivedFrom": "selection.byHarm",
   "harms": [
    "exposure"
   ]
  },
  {
   "id": "A2",
   "name": "Browser extension, content-script only",
   "tools": "A folder with a manifest and one script, loaded unpacked",
   "mechanism": "friction",
   "mechanismProse": "Whatever you can do to a page you are already looking at: a delay before the feed appears, a prompt asking what you came for, an element removed on a schedule, a count kept locally.",
   "setup": "Create a folder with three small files and load it unpacked from the browser's extensions page. No store submission, no signing, no build step.",
   "platforms": [
    "macos",
    "windows",
    "linux"
   ],
   "securityProfile": "Excellent, but conditionally: only if the manifest declares specific host permissions rather than a wildcard, and declares no network permission at all. With those two properties the extension structurally cannot exfiltrate anything, whatever bugs it contains — and you can verify that by reading one short file.",
   "effort": "an evening",
   "writesCode": true,
   "requiresReview": "Read the manifest before loading it. The two lines that matter are the host permissions and the absence of any network permission.",
   "why": "The most capable thing on this list that is still auditable in one sitting, and the only one that can implement interruptive friction — the intervention class with the strongest published evidence behind it.",
   "harmsDerivedFrom": "selection.byHarm",
   "harms": [
    "time_displacement",
    "interference",
    "exposure"
   ]
  },
  {
   "id": "A3",
   "name": "New-tab or homepage replacement",
   "tools": "One local HTML file",
   "mechanism": "self_regulation",
   "mechanismProse": "Intention-setting at the exact moment the habit fires. The new tab is the most-visited page most people have, and by default it is a launcher for the thing they are trying not to open.",
   "setup": "One HTML file on your own disk, set as the new-tab or homepage.",
   "platforms": [
    "macos",
    "windows",
    "linux"
   ],
   "securityProfile": "Trivial. A local file with no permissions of any kind and nothing to grant.",
   "effort": "an hour",
   "writesCode": true,
   "why": "Cheap, completely safe, and aimed at interference specifically — it acts at the moment of the reach rather than after it.",
   "harmsDerivedFrom": "selection.byHarm",
   "harms": [
    "interference"
   ]
  },
  {
   "id": "B1",
   "name": "hosts-file block",
   "tools": "A text editor and one sudo command",
   "mechanism": "access_control",
   "mechanismProse": "Blocks a domain for every application on the machine, not just the browser. Covers the desktop app you forgot was installed.",
   "setup": "Edit one system file with administrator rights.",
   "platforms": [
    "macos",
    "windows",
    "linux"
   ],
   "securityProfile": "Needs sudo, which is why it comes with two hard requirements: the block must be written inside sentinel comments so removal is a deterministic delete, and the revert must be a single command given at the same time as the install. A malformed hosts file can break name resolution for the whole machine.",
   "warning": "This is the only recipe on this site that touches a system file. If it goes wrong, networking on the machine stops working until the file is fixed — so keep the revert command where you can find it without the internet.",
   "effort": "minutes",
   "writesCode": false,
   "why": "Whole-machine coverage with no software installed and nothing running in the background.",
   "harmsDerivedFrom": "selection.byHarm",
   "harms": [
    "time_displacement",
    "boundary"
   ]
  },
  {
   "id": "B2",
   "name": "DNS-level blocking",
   "tools": "NextDNS, Pi-hole, or AdGuard Home",
   "mechanism": "access_control",
   "mechanismProse": "The same idea as the hosts file, at the network layer: passive, whole-machine, and where it runs on your router, whole-household and every device on it — including the phone this site cannot help you build for.",
   "setup": "Configuration only. No code at all.",
   "platforms": [
    "macos",
    "windows",
    "linux"
   ],
   "securityProfile": "Safe, with one thing worth knowing plainly: a hosted resolver sees every domain your devices ask for. That is a meaningful amount of information about you, held by a company. A self-hosted resolver on your own network does not have that property, at the cost of running it yourself.",
   "effort": "an hour",
   "writesCode": false,
   "why": "The only recipe here that reaches your phone without installing anything on your phone.",
   "harmsDerivedFrom": "selection.byHarm",
   "harms": [
    "time_displacement",
    "boundary",
    "exposure"
   ]
  },
  {
   "id": "B3",
   "name": "Scheduler",
   "tools": "launchd, Task Scheduler, or a systemd timer",
   "mechanism": "access_control",
   "mechanismProse": "Applies any of the other recipes on a schedule, so the constraint arrives at 9pm without you deciding anything at 9pm. This is the recipe that fits work bleeding into the evening.",
   "setup": "Install one plist, one scheduled-task XML, or one systemd unit and timer.",
   "platforms": [
    "macos",
    "windows",
    "linux"
   ],
   "securityProfile": "Local only, no elevated permissions needed for a user-level job, and nothing runs except the small script you wrote. Moderate only in that a misconfigured schedule is annoying rather than dangerous.",
   "effort": "an evening",
   "writesCode": true,
   "why": "Lets the calm self author the rule and the tired self encounter it, which is the point of the whole exercise.",
   "harmsDerivedFrom": "selection.byHarm",
   "harms": [
    "time_displacement",
    "interference",
    "boundary"
   ]
  },
  {
   "id": "B4",
   "name": "Greyscale on a schedule",
   "tools": "A small script plus a scheduler",
   "mechanism": "friction",
   "mechanismProse": "Environment-level friction that is not a block. It does not stop you doing anything; it makes the parts of the interface engineered to be rewarding stop being rewarding.",
   "setup": "A few lines of script, plus B3 to run it on a schedule.",
   "platforms": [
    "macos",
    "windows",
    "linux"
   ],
   "securityProfile": "Very safe. Toggles a display setting and nothing else. No permissions, no data, nothing persistent.",
   "effort": "an hour",
   "writesCode": true,
   "why": "Cheap, reversible, badly under-used, and one of the few things here that reduces pull without removing capability — so there is nothing to resent and nothing to bypass.",
   "harmsDerivedFrom": "selection.byHarm",
   "harms": [
    "interference",
    "boundary"
   ]
  },
  {
   "id": "B5",
   "name": "Cost-of-exit wrapper",
   "tools": "A small script — a passphrase, a timed delay, or a file on removable media",
   "mechanism": "access_control",
   "mechanismProse": "Wraps any of the above in something that makes undoing it deliberate rather than impulsive: a delay before the disable takes effect, a passphrase written on paper in another room, a key file on a USB stick you keep in a drawer.",
   "setup": "A small script around whichever recipe you chose.",
   "platforms": [
    "macos",
    "windows",
    "linux"
   ],
   "securityProfile": "No privileged operations. The cost of exit must be inconvenience, never a real lock — nothing here should be able to stop you getting to your own machine.",
   "warning": "Do not let a model design you something genuinely irreversible. A constraint you cannot undo on your own computer either needs privileges you should not grant, or becomes a real problem in an emergency. Deliberate friction is the goal; a lock is not.",
   "effort": "an evening",
   "writesCode": true,
   "why": "This is the recipe that directly implements the autonomy slider: it is how you get a limit that holds without handing control to a company. Almost nothing on the commercial market offers a real cost of exit, and this is the honest way to get one.",
   "harmsDerivedFrom": "selection.byHarm",
   "harms": [
    "time_displacement"
   ]
  },
  {
   "id": "B6",
   "name": "Shell or editor friction",
   "tools": "A shell function or a git hook",
   "mechanism": "friction",
   "mechanismProse": "Friction placed in the tools a developer already lives in.",
   "setup": "A few lines in a shell profile or a hook file.",
   "platforms": [
    "macos",
    "windows",
    "linux"
   ],
   "securityProfile": "Local only, no permissions, and entirely inside files you already own.",
   "effort": "minutes",
   "writesCode": true,
   "audience": "developers",
   "why": "Narrow, but for the people it fits it is the lowest-friction thing on the list.",
   "harmsDerivedFrom": "mechanism — this recipe is in no byHarm list",
   "harms": [
    "time_displacement",
    "interference"
   ]
  }
 ],
 "refuse": {
  "note": "Out of scope. The generator must refuse these and say which rule, rather than finding a way around them. This list is restated verbatim inside every generated prompt.",
  "items": [
   "Anything requiring macOS Accessibility or Screen Recording permission",
   "Windows global input hooks or keyboard/mouse interception",
   "Android AccessibilityService, device-admin, or usage-stats access",
   "Kernel extensions, system extensions, or network filter drivers",
   "Unsigned native binaries",
   "Electron or Tauri applications",
   "Any outbound network request, of any kind, for any reason",
   "Any server, account, or sync feature",
   "Clipboard monitoring, screenshot capture, camera or microphone access"
  ],
  "whyRefusalIsThePoint": "Some of these would make a better blocker. That is precisely why they are excluded: a person cannot meaningfully audit a tool holding those permissions, and habituating someone to granting them is a harm that outlives the tool."
 },
 "contextSelection": {
  "note": "Which files from the agent context pack go into the generated prompt. security.md and desktop-surfaces.md are always included because the prompt is unsafe without them; the rest are selected by what the user actually said, so the paste stays a workable size.",
  "always": [
   "security.md",
   "desktop-surfaces.md",
   "design-principles.md"
  ],
  "byCondition": {
   "axes.md": "always — the autonomy, negotiability and cost-of-exit framing is what the interview needs to elicit",
   "mechanisms.md": "always — the four-harm distinction is what keeps the model from proposing a general-purpose tool",
   "failure-modes.md": "when the user reported any previous failure",
   "evidence.md": "when the user's goals include feeling less anxious, or severity is signposted — it is the file that says which claims to stop making"
  }
 },
 "stage1Instructions": [
  "Interview me before proposing anything.",
  "Ask no more than six questions, one at a time, and wait for my answer before the next one.",
  "Cover: which surfaces specifically; which times of day; what \"done\" looks like for me; what should happen when I try to bypass it; how I want to turn it off; and what I want the time back for.",
  "Push back if what I ask for contradicts what I said I wanted. If I ask for something that breaks a security rule, name the rule and offer the nearest compliant design.",
  "Do not write any code in this conversation.",
  "When you have enough, output a BUILD SPEC in the format below and nothing else."
 ],
 "buildSpecTemplate": [
  "GOAL — in my words, not yours.",
  "MECHANISM — which one, and why it matches the problem rather than a different one.",
  "SURFACE AND PLATFORM — exactly what it acts on and where it runs.",
  "BEHAVIOUR — what happens, when, and precisely what happens when I try to bypass it.",
  "PERMISSIONS — every permission requested, each with a one-line justification, in plain language a non-programmer can evaluate and decline.",
  "ACCEPTANCE CRITERIA — how I will know it works, stated so I can check each one.",
  "UNINSTALL — the exact steps to remove it and restore the prior state, to be tested before relying on the tool.",
  "SECURITY CONSTRAINTS — the seven rules, restated verbatim."
 ],
 "stage2Handoff": [
  "Paste the BUILD SPEC into a coding agent — Claude Code, Cursor, or similar.",
  "Ask for a plan before any implementation, and read the plan.",
  "Read the diff. If it is longer than about 200 lines, ask why, and ask for the smaller version.",
  "Check the manifest or the script header yourself for two things: no network permission, and no permission broader than the one surface you named.",
  "Run it locally and check it against the acceptance criteria one at a time.",
  "Test the uninstall BEFORE you start relying on the tool. A tool you cannot remove is worse than no tool.",
  "Come back in two weeks and ask whether it is still doing anything. Most of these stop working and nobody notices."
 ]
}