Skip to content

Agent guidance (AGENTS.md)

This repo is built primarily by AI agents with human review. The docs are the spec; the tests are the law. Read this file fully before changing code.

  1. Protocol changes are allowed, but never accidental. This is still a green-field system, so do not let wire-format work become a blocker when a refactor or protocol change is the right design. The tests/test_packet.cpp::packet_golden_bytes test pins LPP v1 byte-for-byte; if your change breaks it or changes any parsed packet payload, update docs/PROTOCOL.md, apply the wire-change checklist, bump/version the design when compatibility requires it, and say so loudly in your PR. Never “fix” the golden test to match new bytes without documenting the protocol event.
  2. Core stays portable. core/ must compile for ESP32/nRF52/POSIX with no Arduino.h, no sockets, no exceptions/RTTI-dependent constructs, no hidden allocation on the radio path. Platform access goes through the seams in core/include/lrc/types.h (Clock, Rng) and caller-provided buffers. Heap/std::string are allowed only in the IRC gateway layer (core/src/irc/) and above.
  3. Docs and code move together. Every behavioral change updates the matching file in docs/ in the same commit. The docs are normative; reviewers diff them first.
  4. Every feature lands with tests. Unit tests in tests/ (framework: tests/lrctest.h, zero deps). Cross-node behavior goes in tests/test_node.cpp (in-process network simulation — preferred) or tests/smoke_lrcd.py (real sockets). If you can’t test it on the host, refactor until you can; that’s the architecture working as intended.
  5. RF safety is not reviewable by CI. Anything touching firmware/variants/, RF-switch handling, TCXO voltage, or TX paths needs a human sign-off and a pointer to the rule in docs/HARDWARE.md you’re honoring. When in doubt: receive-only defaults.
  6. No new dependencies without discussion. Current external surface: RadioLib (firmware), vendored orlp/ed25519. That’s it on purpose.
Terminal window
cmake -S . -B build && cmake --build build -j # must be warning-clean (-Werror)
./build/lrc_tests # all green, always
python3 tests/smoke_lrcd.py # if you touched daemon/ or irc/
(cd firmware && pio run) # if you touched core/ or firmware/
You’re changing… Read first Tests to extend
wire format / codec docs/PROTOCOL.md test_packet.cpp
keys, tags, signatures docs/IDENTITY.md test_crypto.cpp
registration handshake docs/IDENTITY.md §2 test_reg.cpp
dedup/frag/seq recovery docs/PROTOCOL.md §Recovery test_transport.cpp
CHANSYNC / gap healing docs/PROTOCOL.md §Recovery test_node.cpp (node_gap_heals_via_chansync)
lane plans / schedule / airtime docs/RADIO.md test_lanes.cpp
flash message store docs/STORAGE.md test_lrclog.cpp
IRC behavior docs/ARCHITECTURE.md §IRC gateway test_irc.cpp
TUI docs/ARCHITECTURE.md §The TUI test_tui.cpp
node glue / federation docs/ROUTING.md test_node.cpp + smoke_lrcd.py
firmware docs/HARDWARE.md + POWER.md host tests still gate; hardware notes in PR
  • C++17, 4-space indent, ~100 col. Match the file you’re in.
  • Comments explain constraints and why, not what the next line does. The codebase deliberately reads as documentation for the next agent — keep that bar.
  • Counters: any new observable behavior gets a lrc::Counter and shows up in stats for free. Stable names are API (docs/TELEMETRY.md).
  • Commit messages: area: what changed plus a body that names the invariants you preserved (golden bytes, portability, RF safety).
  • SEQ3 = 0xFFFFFF sentinel everywhere: “not yet sequenced” — see PROTOCOL.md before “fixing”.
  • Tags computed over the unstamped canonical image: the router rewrites SEQ3 after signing; this is by design (IDENTITY.md §7).
  • The dedup ring accepting a bounded false-negative rate: documented trade in dedup.h.
  • *lrc service nick violates RFC nick grammar: deliberate — it can never collide with a real user.

.claude/skills/ contains task recipes (lrc-wire-change, lrc-add-test). If your harness supports skills, use them; they encode the checklists above.