Instructions for any AI coding agent working in this repo (Claude Code, Codex, Cursor, Gemini CLI, β¦). Read this before starting work, and follow the gates in "Submitting a PR" before proposing that a change is ready.
- Keep in-code comments short β 5 lines max. Deeper rationale belongs in the PR description, not in the source.
- No speculative guards. Do not add defensive code for failure modes that cannot realistically occur. Prefer the simpler path.
- Verify before implementing. On design tasks, check feasibility against the real API source (not memory, not docs summaries) and confirm the approach before writing code.
- No code duplicates. Re-use existing code and logic where applicable.
- Protect latency. Keep database and external I/O outside shared locks unless ordering requires it; preserve lifecycle serialization and bound concurrent work.
- Check performance regressions. For routing, storage or lifecycle changes, compare encrypted cold/warm concurrent load and teardown timings, including errors and cleanup, before declaring ready.
Four gates, in order. A clean build and passing unit tests are not sufficient evidence to open a PR β they are the floor, not the bar.
Do not write a fix before the failure has been reproduced.
- State the reproduction, the observed behavior, and the expected behavior.
- If the issue came from a report, confirm the reported cause is the actual cause. Several past investigations found the stated theory was wrong.
- If you cannot reproduce it, stop and say so rather than fixing speculatively.
Gate 2 β static soundness and hidden-regression hunt
Before touching the lab with Linux boxes for end-to-end verification:
- Re-read the changed code as a reviewer would. Does it hold under concurrency, restart, and partial failure β not just the happy path?
- Hunt for regressions the change could cause elsewhere as side effect: ordering assumptions, cleanup/teardown paths, anything that shares state with what you touched.
- Run the full CI command set.
Every change ships only after it has run end-to-end on real hosts.
- The gRPC control channel is TLS. Each host needs
JWT_SIGNING_KEY,MFA_ENCRYPTION_KEY,CONTROL_SERVICE_TLS_SAN, andca-cert.pempresent in/root/nullnet/, plus a rebuilt proxy. See SETUP.md for the full setup. - Verify client restart recovery without restarting application containers; startup cleanup must preserve Docker-owned interfaces and routes.
- To restart a Swarm stack, use
docker service update --force. - The default-deny eBPF firewall blocks Swarm ports.
2377,7946, and4789must be in the.envallowlists on strict nodes, or the worker goes Down.
Report the actual observed result under load with a complex service topology β the before/after numbers, the log lines, the
/api/graph/{stack} state. "It works" is not a verification.
A change that is invisible when it misbehaves is not finished.
- Emit an event for the cases an operator would need to see. New failure
modes, and state transitions that are otherwise silent, belong in the
Eventenum inmembers/nullnet-server/src/events.rs, with aSeveritythat matches how much attention the case actually deserves. Reuse an existing variant when one fits. - Use judgment, not coverage. Events serve someone debugging a live network from the Events tab β not routine per-request or per-packet activity, and not general telemetry. Anything that is not Events-tab material gets a dedicated RPC instead.
- The proto-to-server half of a new event fails to compile if you miss a step;
the UI half does not. Finish it in
nullnet-server/ui/src/: the member intypes.ts, and both a filter entry and a render arm inpages/Events.tsx. Otherwise, the event is emitted and silently never shown. - Update
SETUP.mdwhen the change alters set up and configuration, but only include the essential info without being verbose. - Update
CHANGELOG.mdwith a one-line description of the change, following the existing format, and including a link to the PR and the issue it fixes (if any).
A change is done when all four gates have passed and the end-to-end evidence is written down. Anything short of that is reported as in-progress, with the specific gate it is blocked on.