Coding Standards
This page is a digest. The full standard is the set of files in
practices/ in the
repository, one file per language or surface, and every pull request is
reviewed against those files. Read the file for the language you are touching
before writing code; this page tells you what to expect from it.
Full text: practices/go.md
and practices/architecture.md.
- Interfaces are defined at the consumer side (
EventBuslives where the domains that call it live), kept small (1–3 methods), and returned as structs, accepted as interfaces. - Sentinel errors (
ErrNotFound,ErrConflict,ErrUnauthorized), wrapped with context at the boundary; event handlers distinguishErrRetryablefromErrFatal. log/slogonly — no third-party logger, nofmt.Println. Every request or message handler carries atrace_id-scoped child logger throughcontext.Context.- Constructor injection, no global singletons, no DI framework.
- Table-driven tests with
testify(requirefor preconditions,assertfor checks). - Queries are hand-written
.sqlfiles;sqlcgenerates the typed Go. See ADR 0009.
React (the Frontend Commandments)
Section titled “React (the Frontend Commandments)”Full text: practices/react-guide.md.
F1–F7 are hard rules for anything in web/ — a PR that breaks one is not
done, regardless of what nearby code does:
- F1 — Page → Feed → Section → Card. Every screen decomposes into named,
single-responsibility components; no inline
.map()rendering a<section>or large JSX block. - F2 —
&&, negative-first. Loading → error → empty → data, each its own&&block. Noif (x) return <Component/>for rendering. - F3 — Shared display components.
LoadingDisplay,ErrorDisplay,NoDataDisplay,Container— never hand-rolled equivalents. - F4 —
&&for components, ternaries only for values. Never a ternary choosing between two components. - F5 —
useState/useEffectare a last resort. Server state lives in TanStack Query, cross-surface state in Zustand, form state in React Hook Form; effects are for real side effects only. - F6 — No prop drilling. Past ~2 levels, the child fetches its own data or reads a store instead.
- F7 — Files own one concern. Pages stay thin; sub-components live in
components/<domain>/.
TypeScript outside the browser
Section titled “TypeScript outside the browser”Full text: practices/typescript.md.
The SDK and the automations host run on Bun and test with bun test; the
desktop shell is Electron with the same strictness flags as the web app and
the Electron security checklist (context isolation on, node integration off,
a preload bridge with an explicit allow-list) stated as absolutes.
Testing
Section titled “Testing”Full text: practices/testing.md.
Coverage (80% gate, 90% target) is a floor, not a goal — error paths, state transitions, and idempotency come before happy paths. Mock at the interface boundary; prefer fakes over mocks for repos. A flaky test is a bug: fix it or delete it, never skip or retry-mask it.
Design language — the Mono Console
Section titled “Design language — the Mono Console”Full text: practices/design-language.md.
Nexul is strictly monochrome and dark-first, with no accent color
anywhere in the chrome — near-black or near-white surfaces, true mirror
inversions of each other, layered by 1px hairlines rather than blur shadows.
Technical data (ids, repos, timestamps) is set in JetBrains Mono, and code
or log surfaces read like terminal windows. Color is reserved entirely for
badge and status signal, never for chrome decoration — extend the token set
in web/src/index.css when a design needs one, never re-theme with a new
hue.
What enforces the rules
Section titled “What enforces the rules”A rule a linter can check is checked by a linter. Go runs golangci-lint
(config in .golangci.yml) and govulncheck in CI and through make lint
and make vuln; the coverage gate is make coverage; sqlc vet and
sqlc diff keep generated code honest. Every TypeScript package runs its
typecheck and test scripts in CI, and Dependabot opens grouped weekly
update pull requests per directory.
Hard rules from AGENTS.md
Section titled “Hard rules from AGENTS.md”These apply everywhere, regardless of surface:
- Early return, no
else. In Go and TypeScript alike — handle the exceptional case and return, leave the happy path unindented. - No barrels. No
index.tsre-export files. Import by full path. - Structured logging.
slogin Go, console with a propagatedtrace_idin TypeScript. Nofmt.Println, noconsole.login production code. - Comments are sparse. Default is no comment. One exists only to say a why, a non-local warning, or a pointer — never to restate the code, never a change-history note, one line, and no commented-out code.
- Mobile-first. Design and build at 320 / 375 / 414px first; verify at 320 / 375 / 414 / 768px before calling web work done.