The Rulebook
The non-negotiable invariants every AI coding session must follow before it writes a line — and why each one is machine-checkable, not just written down.
Every Foxx Cyber repository carries a CLAUDE.md — a file the AI assistant is
instructed to read before touching code. It isn't aspirational. It's the
contract, and the rules that matter most are enforced by machines that don't
get tired.
The rules below are the actual invariants from HLE-AIO, our reference application. Other products carry the same shape adapted to their stack.
The non-negotiable invariants
- Tenant scoping on every query. A tenant identifier (for HLE-AIO, a
household ID) is never accepted from the client. Every scoped query —
including the
WHEREclause of everyUPDATE/DELETEby id — carries the server-derived scope. This is the single most important rule in the codebase, and it exists because a cross-tenant data-exposure bug happened once, early on. It is now guarded by a regression test and a CI check. - Auth gate first. Server functions compose auth / admin / tenant middleware from one place. There is no unauthenticated server function outside login, first-run setup, and the health check.
- Parameterized SQL only. Queries use tagged-template parameterization. User input is never interpolated into a query string. No raw string-built SQL anywhere in the codebase.
- Validation at the boundary. Every server function validates its input against a schema before the handler runs, so malformed or hostile input never reaches business logic.
- Migrations are append-only. Editing an already-applied migration is treated as drift and is a hard startup error. You write a new migration instead — the schema's history stays truthful.
- Audit the security-relevant events. Anything touching login, sessions, passwords, user or tenant administration, backups, or destructive deletes is written to an append-only audit log.
- No rule suppressions, ever. No
eslint-disable, no@ts-ignore, no@ts-expect-error, no@ts-nocheck, no explicitanyto dodge the type checker. This rule exists because I watched an AI assistant almost ship suppressions to make a warning go away. That's exactly how unreviewed code sneaks past the gates — so it's banned, and the ban is enforced in CI.
Rules 1–4 are the ones that prevent the classic AI-generated-code failures: broken multi-tenant isolation, missing authorization, and injection. They are stated as invariants precisely because an AI assistant, left to pattern-match, will occasionally produce a handler that looks right and quietly omits one of them. The rule makes the omission a violation instead of a judgment call.
Why "written down" isn't enough
A CLAUDE.md sentence is a good start, but prose can be forgotten between
sessions and can't fail a build. So wherever a rule can be turned into a
machine check, it is:
| Rule | How it's enforced by a machine |
|---|---|
| No rule suppressions | CI greps every change for the forbidden tokens; a match fails the build |
| Parameterized SQL only | Same diff-grep gate flags raw SQL string-building |
| No unsafe HTML sinks | Diff-grep flags dangerouslySetInnerHTML |
| Tenant scoping | Regression test reproducing the original cross-tenant bug + invariant tests over the query layer |
| Migrations append-only | Checksum drift detection aborts startup |
| Type safety | tsc --noEmit in CI, no suppressions permitted to pass it |
The principle: a lint rule beats a CLAUDE.md sentence, and a CI job beats
both. The written rule teaches the intent; the machine check makes backsliding
impossible.
The pre-flight every change runs
Before any change is declared complete, the assistant runs — and I verify the output of — the project's full pre-flight. For HLE-AIO that's a single command:
bun run typecheck && bun run lint && bun run check && bun run test"It should work" is not an acceptable answer. The verification has to be actual, and the output has to be read. When the pre-flight and the CI guardrails both pass on a change I've read and understood, it can land — and not before.
Every security fix gets a regression test
When a bug crosses a security boundary — auth, tenancy, injection — the fix isn't done until there's a test that fails on the pre-fix code. That test is the only thing that reliably prevents the same class of bug from shipping twice, in this codebase or the next one the AI works in.