close
Skip to content

Repository files navigation

You Shall Not Code

A desktop commitment gate. You write a task; coding tools stay locked until it is done.

When you finish, the app always texts the person you named. Tools unlock after that text is accepted.

If you give up instead, you choose:

  1. I can give up without a reply — unlock from this computer. They still got (or will get) the completion texts; they do not have to text yes.
  2. They have to reply yes if I give up — no unlock button on this computer. Their yes is recorded on a website you do not control.

Existing installs that already had texts plus the yes/no website stay on the hard give-up path until you switch.

The app never invents tasks. You create them.

Architecture

Desktop UI (Tauri + React)
        ↓
Local enforcement service (Rust)
        ↓
Commitment state (SQLite + HMAC lockfile)

FastAPI backend: override authorization + Sendblue inbound webhooks

Closing the GUI does not unlock tools. The background enforcer keeps watching processes.

Install it without a terminal

If you want giving-up to require their yes (rather than unlocking yourself), see docs/DEPLOY.md for hosting the yes/no website. Everyone still sets up texts in the app. Tag a release so GitHub builds the Windows and macOS installers.

The rest of this file is for working on the code.

Prerequisites

  • Rust (stable)
  • Node.js 20+
  • Python 3.11+
  • A Sendblue account (iMessage / SMS)

Run locally (Windows)

From the repo root:

python scripts/make_icons.py
cargo build -p ysnc-enforcer
cd backend
python -m venv .venv
.\.venv\Scripts\activate
pip install -r requirements.txt
copy .env.example .env
python ..\scripts\gen_secrets.py   # paste the three secrets into .env
# then add your Sendblue key id, secret and from-number
uvicorn app.main:app --app-dir . --host 127.0.0.1 --port 8787

The backend refuses to start until OVERRIDE_SIGNING_SECRET, SENDBLUE_WEBHOOK_SECRET and CLIENT_API_TOKEN are set to real values. An unauthenticated webhook would let anyone approve an override, so there is no permissive default.

In a second terminal:

cd desktop
npm install
npm run tauri dev

The desktop app will try to spawn ysnc-enforcer. On first launch, Setup asks you to install the background lock so it survives reboot.

Run locally (macOS)

Same steps, with:

python3 -m venv .venv
source .venv/bin/activate
cp .env.example .env
uvicorn app.main:app --host 127.0.0.1 --port 8787

The enforcer installs a LaunchAgent at ~/Library/LaunchAgents/com.youshallnotcode.enforcer.plist.

First-run setup

Open the app. Setup always asks for you, a person, texts, and the background lock.

When you finish a task, that person gets a text. Every time.

Then it asks what happens if you give up:

I can give up without a reply — those four steps. No website.

They have to reply yes if I give up — the same four, plus the public yes/no website URL and the two passwords from your host.

Hosting steps for that extra website are in docs/DEPLOY.md. Settings is for later edits, including switching the give-up rule.

Credentials go to the OS keychain (Windows Credential Manager / macOS Keychain). Where no keychain is available, or when YSNC_DATA_DIR is set for a self-contained install, they are files in the app data folder instead — owner-only on macOS and Linux. Settings states which of the two is in use rather than claiming the keychain unconditionally. Nothing is hard-coded.

MVP test

  1. Create a commitment: Send 5 cold emails before coding
  2. Coding agents (Codex, Claude Code, Cursor, Windsurf, Gemini CLI, Aider, plus any custom executable) are blocked
  3. Try launching one → notification: CODING LOCKED / Complete first: …
  4. Do the task outside the app
  5. Press I finished
  6. Sendblue sends the completion message — this happens in both modes
  7. On Sendblue success, tools unlock immediately

If you chose I can give up without a reply, I didn’t — unlock myself still texts them the override notice, then unlocks. They do not have to reply.

If you chose They have to reply yes if I give up:

  1. Press Request override and give a reason
  2. That person receives the request and replies APPROVE ABC123 or DENY ABC123
  3. Tools stay locked until the backend records a signed approval
  4. The local app cannot approve an override

For a safe first block test, add notepad.exe (Windows) or TextEdit (macOS) as a custom executable instead of locking Cursor while you are still developing this repo.

Override webhook

The backend must be reachable by Sendblue:

POST /webhooks/sendblue

Point a public HTTPS URL (Cloudflare Tunnel, ngrok, or a deployed host) at that path, then configure it as a Sendblue receive webhook with SENDBLUE_WEBHOOK_SECRET.

An inbound reply is accepted only when both hold:

  • the sender is one of the numbers the request was actually sent to, and
  • the reply quotes the code for one of that sender's pending requests.

A wrong code is a refusal, never a fallback to the sender's most recent request. Registering an override for a commitment that already has one is rejected if it names a different contact, so a pending request cannot be re-pointed at a friendlier approver.

The desktop enforcer polls GET /overrides/{id} (bearer token) and unlocks only when the HMAC signature verifies and the approver is one of that commitment's contact numbers. There is no local approve API.

If the backend was unreachable when the request was made, the enforcer notices the missing registration on its next poll and re-registers it; Today shows a warning until it lands.

Tamper handling

The lock does not live in the database alone. A signed lock.json records which database it belongs to and which commitments were holding the lock, so:

  • deleting or replacing ysnc.db is detected instead of unlocking,
  • deleting a locked row is detected,
  • editing any commitment field (including evidence, delivery status and override metadata) breaks its signature,
  • an unreadable lock.json counts as locked.

A detected tamper writes tamper.json and keeps everything locked across restarts. In someone else mode, clearing it needs the same external approval as any override — Today shows a panel to ask a contact — and your person is texted once when it happens. In I’ll unlock myself mode, Home has a button to clear it here.

Wiping the whole app data folder is uninstall, and uninstall stays easy on purpose.

Tests

cd desktop && npm run sidecar            # stage the enforcer; the desktop crate needs it
cd .. && cargo test --workspace --all-targets   # core, enforcer, packaging guards
cd backend && pip install -r requirements-dev.txt && python -m pytest -q
cd ../desktop && npx tsc --noEmit

npm run sidecar builds ysnc-enforcer and stages it where Tauri expects it. npm run tauri build runs it automatically; a bare cargo build of the desktop crate does not, and fails until it has been run once.

Uninstall

This is not malware-style persistence.

  • Remove login item in Settings (only while unlocked)
  • Delete the app
  • Windows: HKCU\Software\Microsoft\Windows\CurrentVersion\Run\YouShallNotCodeEnforcer
  • macOS: unload and delete ~/Library/LaunchAgents/com.youshallnotcode.enforcer.plist

Messaging

Sendblue only. The provider is behind a small MessagingProvider trait / protocol so another vendor could be added later. Twilio is not integrated.

gstack

AI-assisted work in this repo uses gstack, vendored as a git submodule at gstack/. After clone:

git submodule update --init --depth 1 gstack

Cursor wrappers live in .cursor/skills/. Slash commands such as /design-review load gstack/<skill>/SKILL.md.

Product rule

Do the hard task and publicly declare it, or admit failure and ask another human.

Quietly escaping into coding tools is the option this app removes.

About

Do not vibe code before you actually do something yourself!!!

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages