The README was two documents in one, and neither reader was served by the other's half. It opened on a feature list, then spent its second half on Go versions, WebKitGTK packages and `make` targets — while its install table named a `darwin-universal.app.zip` and a `windows-amd64.exe` that nothing has ever produced, and its header claimed Windows and never mentioned Android, which is the one platform with a published, self-updating channel. So this is a correctness pass as much as a friendliness one. The README now answers a user's questions only: what the app is, three screenshots from the seeded fixture library so anyone can retake them, the four formats, one install section per channel that names what is actually published, first run, where the data lives, and pointers out. The version-restart note is linked to the two documents that own it rather than copied, because a copy is a second thing to keep true. CONTRIBUTING.md takes the technical half: prerequisites, the system libraries, the build and codegen commands, which verification tier a change demands, the tracker workflow, the commit grammar and the style rules. CLAUDE.md is unchanged apart from one paragraph naming the split — it was already the deep reference both of the others point at, and stays the only one of the three that explains why a shape is what it is. Closes #50
174 lines
7.9 KiB
Markdown
174 lines
7.9 KiB
Markdown
# Contributing to YellowJacket
|
|
|
|
This is the contributor's half of the [README](README.md): how to build it, how
|
|
to check a change, and how a change gets in. [`CLAUDE.md`](CLAUDE.md) is the
|
|
deep reference — the architecture, and the reasons behind the shape of it —
|
|
and is worth reading before a change of any size, because most of this
|
|
codebase's traps are written down there and nowhere else.
|
|
|
|
## Building from source
|
|
|
|
YellowJacket is [Go](https://go.dev/) with a [Lit](https://lit.dev/)/TypeScript
|
|
frontend, bridged by [Wails v3](https://wails.io/).
|
|
|
|
| Tool | Version |
|
|
|------|---------|
|
|
| Go | 1.25+ |
|
|
| Node.js | 22+ |
|
|
| pnpm | 10+ |
|
|
| Wails CLI | v3 — vendored, no install needed (`go tool wails3`) |
|
|
|
|
The Wails v3 CLI resolves from the `tool` block in `go.mod`, so there is nothing
|
|
to install globally; `make setup` fetches it with the rest of the tooling.
|
|
|
|
On Linux, install the system libraries Wails needs. v3 builds against GTK4 +
|
|
WebKitGTK 6.0 by default:
|
|
|
|
```bash
|
|
sudo apt-get install libasound2-dev libgtk-4-dev libwebkitgtk-6.0-dev # Debian/Ubuntu
|
|
sudo pacman -S alsa-lib gtk4 webkitgtk-6.0 # Arch
|
|
```
|
|
|
|
A machine without `webkitgtk-6.0` can still build with `-tags gtk3` against the
|
|
older WebKit2GTK 4.1 stack, but that is an escape hatch, not what CI or a
|
|
release builds. macOS and Windows need no extra system packages. Run
|
|
`go tool wails3 doctor` to check your environment.
|
|
|
|
```bash
|
|
make setup # install tooling, frontend packages and the git hooks
|
|
make dev # run with hot-reload
|
|
make build-dev # debug build with symbols
|
|
make build-prod # production build (stripped and trimmed)
|
|
make android # the arm64 APK, into bin/
|
|
```
|
|
|
|
The `Makefile` is the front door and carries a one-line description against
|
|
each target; `Taskfile.yml` and `build/<platform>/Taskfile.yml` are the build
|
|
implementation behind it and are not called directly.
|
|
|
|
## Generated code
|
|
|
|
Two generators run from `go generate ./...`, which `make generate` wraps:
|
|
**sqlc** turns `backend/database/sql/queries/` into Go in
|
|
`backend/database/sql/sqlcgen/`, and **templ** turns `.templ` files into
|
|
`*_templ.go` beside them. Never edit either output by hand — run
|
|
`make generate` after touching a `.sql` or a `.templ` file.
|
|
|
|
The TypeScript bindings in `frontend/bindings/` are generated by `wails3`
|
|
rather than by `go generate`, so they are a separate step: `make bindings`
|
|
regenerates them and `make bindings-check` fails if they are stale.
|
|
`frontend/src/events.ts` is generated too, from `backend/events/events.go`.
|
|
|
|
A pre-commit hook checks that all of this is fresh, so the usual way to meet it
|
|
is a failing commit rather than a bug.
|
|
|
|
## Checking a change
|
|
|
|
Run the tier the change actually demands, not the cheapest one.
|
|
|
|
| Change | Command |
|
|
|---|---|
|
|
| Go | `make lint` and `make test` — both cover all three build configurations |
|
|
| A frontend component or store | `make ui-test` (Vitest in a real Chromium, no backend) |
|
|
| A user-visible flow | `make e2e`, against a running `make dev-headless` |
|
|
| CSS | `make css-check` — see the Chrome 113 note below |
|
|
| Anything cosmetic | look at a screenshot; several bugs here were invisible to every assertion and obvious in an image |
|
|
|
|
`make test` needs the fixture library, which is generated rather than
|
|
committed — it runs `make testdata` itself (about a second).
|
|
|
|
The end-to-end tier drives the real app with no display at all: `make
|
|
dev-headless` starts it in the background on `:34115` (add `SEED=<name>` for a
|
|
seeded library, built by `make sandbox-seed NAME=<name>`), `make dev-logs` tails
|
|
it and `make dev-stop` stops it. **Check the port before starting one** — if
|
|
`:34115` is already answering, someone else's app is there, and a green result
|
|
about their build is worse than no result.
|
|
|
|
Two smaller checks exist because the failure they catch is silent:
|
|
`make bindings-check` (stale generated bindings) and `make css-check`, which is
|
|
two passes — one fails on a `css` literal ended early by a backtick inside a
|
|
comment, the other on a nested CSS rule that begins with a bare element
|
|
selector. Chrome 113 is what the reference Android device renders with, and it
|
|
drops such a rule without a word.
|
|
|
|
`make vulncheck` runs govulncheck over the module.
|
|
|
|
## The issue tracker is the source of truth
|
|
|
|
Work is described by issues before it is described by branches, and the tracker
|
|
is shared with people who cannot see your terminal.
|
|
|
|
- **Search before starting**, closed issues included: `./scripts/issue.sh search
|
|
<terms>`. "That was fixed three weeks ago" is the cheapest possible answer.
|
|
- **Claim before the first edit**, not before the commit:
|
|
`./scripts/issue.sh claim <n>` sets the assignee, applies `Status/In Progress`
|
|
and comments with the branch, so the work is visibly taken *while it is being
|
|
done*. It refuses if somebody else holds it — talk to them rather than working
|
|
around it.
|
|
- **If no issue covers the work, open one first** (`./scripts/issue.sh new`).
|
|
- **Findings get filed.** A bug tripped over on the way to something else is an
|
|
issue with a reproduction, not a wider diff and not a sentence in a chat log.
|
|
- **#73 is the roadmap** and states the order the backlog should be worked in.
|
|
|
|
`scripts/issue.sh` is the whole interface (`list`, `mine`, `search`, `show`,
|
|
`new`, `claim`, `unclaim`, `comment`, `close`, `label`, `depends`, `labels`) and
|
|
wants a `GITEA_TOKEN` with `write:issue`. The labels are a taxonomy rather than
|
|
tags: `Kind/*`, `Area/*`, `Priority/*`, `Platform/*`, plus `Reviewed/*` and
|
|
`Status/*`, of which the last two are exclusive scopes.
|
|
|
|
## Commits and pull requests
|
|
|
|
`main` is protected, so a branch and a PR are the only way in. Branch from
|
|
`origin/main`, and name the branch after the issue (`fix/140-…`, `feat/25-…`).
|
|
|
|
Commit subjects are [Conventional Commits](https://www.conventionalcommits.org/)
|
|
— `type(scope): subject`, imperative, ≤72 characters — and are enforced by a
|
|
`commit-msg` hook and by CI (`make commit-check`). This is load-bearing rather
|
|
than decorative: semantic-release reads the **type** to decide the next version,
|
|
so a CI-only change is `ci:` and never `fix(ci):`, which would ship a patch
|
|
release. `make release-dry` prints what a release would cut right now.
|
|
|
|
**The closing keyword goes in the commit body**, one issue per line, because
|
|
Gitea parses commit messages that reach `main` and does not parse the PR body:
|
|
|
|
```
|
|
docs: rewrite the README as a landing page
|
|
|
|
<why>
|
|
|
|
Closes #50
|
|
```
|
|
|
|
A PR body carries a commit-to-issue table, the verification you actually ran
|
|
(with results), and a `Closes` list for whoever reads it.
|
|
|
|
## Style
|
|
|
|
- **Go** — golangci-lint v2, strict: `err113` (static errors), `nlreturn`,
|
|
`wsl_v5`, `godot`, `sloglint`, `perfsprint`, and imports grouped stdlib →
|
|
third-party → `yellowjacket/…` by gci.
|
|
- **TypeScript** — strict mode, no implicit `any`, no unused locals or
|
|
parameters.
|
|
- Match the surrounding code. Where `CLAUDE.md` explains why something is shaped
|
|
the way it is, that shape is load-bearing and there is usually a test pinning
|
|
it.
|
|
|
|
Hooks do most of the enforcing (`lefthook.yml`, installed by `make setup`):
|
|
pre-commit runs vet, lint, the codegen checks, the frontend typecheck and the
|
|
two CSS checks in parallel; pre-push runs the Go suite and the UI tier,
|
|
deliberately one after the other rather than together.
|
|
|
|
## Where the rest of the documentation is
|
|
|
|
- [`CLAUDE.md`](CLAUDE.md) — architecture and constraints, in depth.
|
|
- [`docs/PROFILING.md`](docs/PROFILING.md) — Go pprof and frontend profiling.
|
|
- [`docs/android-release.md`](docs/android-release.md) — the APK, its signing
|
|
key, and what the release workflow checks.
|
|
- [`docs/index-cache.md`](docs/index-cache.md) — the search-index build cache
|
|
and why it has a snapshot.
|
|
- [`packaging/arch/README.md`](packaging/arch/README.md),
|
|
[`packaging/homebrew/README.md`](packaging/homebrew/README.md) — the two
|
|
package channels.
|
|
- `.planning/` — design documents and measured history, not a queue. The queue
|
|
is the tracker.
|