Skip to content

Contributing

xeri edited this page Jul 14, 2026 · 1 revision

Contributing

Get it building

git clone https://github.com/xeri/proxyforward
cd proxyforward

cd frontend && npm ci && npm run build && cd ..   # do this FIRST
go test ./...
wails dev

You need Go 1.25+, Node.js, and the Wails v2 CLI.

The frontend must be built before any Go command. main.go embeds frontend/dist, which is gitignored, and a go:embed matching zero files is a compile error. On a fresh clone, go build, go vet and go test all fail until npm run build has run once. Everyone hits this exactly once.

The loop

Command What it does
go test ./... The full gate (~35 s): unit, end-to-end, the throughput floor, and the doc-citation check.
go test -short ./... Same, minus the big burst test.
cd frontend && npm run build tsc + vite. This is the only frontend checker — there's no separate lint step.
wails dev The real app, with frontend hot reload.
wails build Produces the exe — and regenerates the Wails bindings, which are committed.
cd frontend && npm run dev The UI alone, in a normal browser, with a mocked Go backend.

That last one is worth knowing about. http://localhost:5173/?mock=agent runs the whole React app against a fake engine, with composable axes for the states that are otherwise a pain to reproduce — ?mock=gateway, ?mock=wizard, &link=down, &fatal=1, &analytics=off, &geo=empty, and more. It's how you check that every surface has a real empty state and a real unavailable state, not just a happy path. WebView2 is not your browser, though — spot-check in wails dev before calling UI work done.

The full command list, with the gotchas, is in docs/agent/commands.md.

What CI will block you on

Everything here is a gate, not advice — see .github/workflows/ci.yml:

  • gofmt, go vet, golangci-lint
  • the full test suite, plus a race-detector run (CI is the only place that runs — it needs cgo)
  • the throughput/latency floor: a large burst through the full tunnel, best-of-three. Never lower the floor to go green.
  • a ban on TODO/FIXME markers
  • a check that the committed frontend/wailsjs bindings aren't stale
  • actionlint

Separately: CodeQL, govulncheck, gitleaks, dependency review and npm audit; the internet-facing parsers are fuzzed nightly; a tag builds a draft release for a human to smoke-test and publish.

Two non-obvious CI facts, both load-bearing:

  • .gitattributes pins eol=lf. Windows runners check out CRLF by default, which makes gofmt reject every file.
  • Every Go job must materialize frontend/dist first, for the go:embed reason above.

House rules

The repository documents itself unusually thoroughly, and those documents are enforced — a test fails the build if the docs cite a file, symbol or test that no longer exists. Before you start, read:

  • CLAUDE.md — the invariants that survive any rewrite (wire protocol, security, liveness, hot path, GUI contract, privacy), and the Reality check table of what's advertised but not built.
  • docs/agent/architecture.md — the map, and "The numbers": the single source for every timeout, cap and buffer size. Change a number there, not in prose somewhere else.
  • docs/agent/reasoning.md — the debugging procedure and the standard of evidence expected before a fix is called a fix.
  • frontend/DESIGN.md — the visual charter. Read it before any UI work.
  • docs/agent/polish-backlog.md — known UX debt. Pull from here before inventing new polish work.

A few rules that will save you a review round:

  • Don't advertise a capability that isn't implemented end-to-end. (This has already gone wrong once — see Not Yet Implemented.)
  • When you implement something from the Reality check, delete its row in the same commit — and please update this wiki's Not Yet Implemented page too. The wiki lives outside the repo's citation test, so nothing will catch it for you.
  • Unknown is a sentinel, never a fake zero. The UI shows "—" when there's no sample. Don't render a 0 ms you don't have.
  • Never add telemetry that leaves the machine. See Analytics and Privacy.
  • Touching the relay, the transport or the counters? Run the burst test before and after.

Good first contributions

  • Anything in docs/agent/polish-backlog.md.
  • The rows in Not Yet Implemented — several are self-contained features with the config and UI already wired, waiting only for an engine.
  • The advertised-but-unimplemented UDP capability is a live protocol bug, not just a doc bug: it's negotiated by both sides and honoured by neither.

License

GPL-3.0. By contributing you agree your work ships under it.

Clone this wiki locally