Skip to main content

Runbook: local development setup on Windows

This runbook sets up sesame-bun on a Windows machine, runs it, and covers common problems. The short version is in the README. Commands are given for PowerShell unless marked Git Bash. Run them from the repository root.

1. Install the prerequisites

The OpenJS.NodeJS.LTS package follows the current LTS line. If it installs a version other than 24, install Node 24 from https://nodejs.org instead. Close and reopen the terminal so the new PATH applies, then check:
Git for Windows also installs Git Bash and openssl, which the Git Bash commands below use.

2. Install the dev tools and prepare the repo

task tools installs the dev tools the other tasks call: linters, formatters and code generators. task setup prepares a fresh clone: dependencies and git hooks. Both are defined in Taskfile.yml; read it for the exact steps and versions. Go tools installed with go install go to the bin folder under go env GOPATH (by default %USERPROFILE%\go\bin). That folder must be on PATH. Check with:
Run task tools again after pulling a change to the tool versions.

3. Create .env

.env is ignored by git. Never commit it and never paste its contents into an issue, PR or log. Task loads the root .env when it runs a task. The backend reads only environment variables and does not open .env itself. If you run the backend binary directly, set the variables in the shell first.

Required variables

UI_PASSWORD_HASH: the argon2id hash of the password you log in with.
Follow the command’s prompt. It prints a PHC string that starts with $argon2id$. Put it in .env in single quotes:
The quotes matter. Task’s dotenv loader expands $name in unquoted and double-quoted values, which would remove parts of the hash. Single-quoted values are read as they are. SESSION_SECRET: at least 32 bytes, hex or base64 encoded. To generate 32 random bytes as hex: PowerShell:
Git Bash:
Both print 64 hex characters. Paste the output as the value.

Optional variables

.env.example has the defaults and accepted values for each variable. The backend refuses to start while GEOBLOCK_URL, POLYMARKET_PRIVATE_KEY, or any POLYMARKET_RELAYER_* or POLYMARKET_BRIDGE_URL variable is set; delete them from an older .env. Leave POLYMARKET_SESSION_KEY empty on this development server. It is in a blocked location, so the Session Key has no use here (security finding F8). The public POLYMARKET_WALLET_ADDRESS alone is enough for positions, activity and P&L; open orders and cash then report credentials_unavailable. Otherwise use task dev:fake for account screens. Setting up real credentials on a host in a permitted location is covered in session-key-setup.md.

4. First run

This starts two processes:
  • the Go backend on 127.0.0.1:8080, serving the REST API under /api and the WebSocket at /ws;
  • the Vite dev server on localhost:5173, which serves the frontend and proxies /api and /ws to the backend.
Open http://localhost:5173 and log in with the password you hashed. Use localhost, not 127.0.0.1 or the machine’s IP address: the Vite dev server binds to localhost only. Check that the backend is up:
In Git Bash: curl -s http://127.0.0.1:8080/api/health. In PowerShell 5.1, curl is an alias for Invoke-WebRequest; use curl.exe for the real curl. The public health check returns only {"status": "ok"} or {"status": "degraded"}. The version, trading state, geoblock result and feed health are on GET /api/status, which needs a session (ADR 0008). After logging in, open http://localhost:5173/api/status in the same browser, or look at the status indicator in the app. On a machine in a location that Polymarket blocks, /api/status shows "trading_enabled": false and "blocked": true, and the startup log records the geoblock status. This is expected; see ADR 0005. Read-only work is unaffected. Stop task dev with Ctrl+C.

Run on a fake venue

For UI work that does not need Polymarket, start the app with:
It runs the same two processes, with the backend started with SESAME_FAKE_VENUE=1 so it takes market data from a fake venue instead of Polymarket. Use it for UI work only; check anything that depends on real venue behaviour with task dev.

5. Everyday commands

6. Regenerate code from the API spec

api/openapi.yaml is the source of truth. The generated code lives in:
  • backend/internal/httpapi/gen (Go, oapi-codegen)
  • frontend/src/lib/api/gen (TypeScript, openapi-typescript)
To change the API, edit the spec and run:
Never edit the generated folders by hand; task gen overwrites them. If the Go or TypeScript build reports a type that does not match the spec after a pull, run task gen.

7. Reset the local database

The SQLite database lives in data/ (or DATA_DIR). Deleting it removes settings, login sessions, the watchlist, layouts, the order audit log and cached market data. The migrations recreate an empty database on the next start.
  1. Stop task dev.
  2. Delete the folder:
    Git Bash: rm -rf data
  3. Run task dev again and log in.
Keep a copy of the folder first if you need the order audit log.

8. Troubleshooting

A port is already in use

The backend needs port 8080 and Vite needs port 5173. Find the process holding a port:
Or: netstat -ano | findstr :8080, then look up the PID in Task Manager. Usually it is an earlier task dev that did not exit. Stop it:
If another program needs 8080, set HTTP_ADDR to another port. The Vite proxy target is configured in the frontend; check frontend/vite.config.ts so that it points at the same port.

The backend exits at startup with a missing or invalid variable

The backend validates its configuration at startup and exits when a required variable is missing or invalid. Check that:
  • .env exists in the repository root (not in backend/);
  • UI_PASSWORD_HASH and SESSION_SECRET are set and not empty;
  • SESSION_SECRET decodes to at least 32 bytes (64 hex characters);
  • you started the backend through Task, which loads .env. go run on its own does not.

Login fails with the right password

  • UI_PASSWORD_HASH is not in single quotes, so $ parts were expanded. Quote it and restart task dev.
  • .env was edited while task dev was running. Task reads .env only at start; restart it.
  • Too many failed attempts. Login is rate limited and returns HTTP 429; wait and try again.

Requests fail with 403 after login

Mutating requests need the session cookie and a CSRF token. If the session has expired, reload the page and log in again.

task or a tool is not recognized

  • task: reopen the terminal after installing, or check winget list --id Task.Task.
  • golangci-lint, gofumpt, oapi-codegen and other Go tools: add the Go bin folder to PATH (section 2) and reopen the terminal.

Trading shows as disabled

Log in, then check GET /api/status (open http://localhost:5173/api/status in the same browser):
  • geoblock.blocked: true: the location is blocked, or the check has not succeeded yet (geoblock.error then holds the reason). Trading stays off. The app has no setting that changes this.
  • LIVE_TRADING is anything other than the exact string true.

Files show as changed right after checkout

.gitattributes checks text out with LF line endings. If your editor saves CRLF, set it to use LF for this repository. Files under testdata/ are kept byte for byte; do not reformat or re-save them.