Skip to content

docs: add CLAUDE.md with project gotchas#55

Draft
skialpine wants to merge 3 commits into
decentespresso:mainfrom
skialpine:docs/claude-md
Draft

docs: add CLAUDE.md with project gotchas#55
skialpine wants to merge 3 commits into
decentespresso:mainfrom
skialpine:docs/claude-md

Conversation

@skialpine
Copy link
Copy Markdown
Contributor

@skialpine skialpine commented May 21, 2026

Summary

Add a CLAUDE.md at the repo root documenting project-specific knowledge that isn't obvious from the source: build/flash commands, code layout (the headers-with-implementations pattern, where setup() and loop() live, what config.h does), the AsyncTCP-task vs main-loop threading model and the wsPendingMask deferral pattern, why WiFi.setSleep(false) is the wrong call with BLE active, ESPAsyncWebServer init ordering, the macOS curl -4 AAAA workaround, AP-mode fallback credentials, a "when X is broken, check Y" table, naming conventions, and a .gitattributes LF-normalization note for bisects.

Distilled from the debugging session that produced #54. Split out as its own PR so #54 stays focused on the firmware change.

Merge order

Land #54 first. This PR documents the WebSocket protocol, deferral pattern (wsReplacePending / processWsPendingCmds / WSP_* bits), WS frame-guard snippet, and corresponding line refs that are introduced by #54. Against bare main the references look forward; against main after #54 lands they're accurate.

Test plan

Generated with Claude Code

skialpine and others added 3 commits May 21, 2026 12:52
Captures project-specific knowledge that isn't obvious from the code:

  * Build / flash / serial commands (including the pyserial workaround
    when pio device monitor can't get a PTY).
  * Code layout: explains the unusual "headers contain implementations"
    pattern, where setup() / loop() live, what's in config.h.
  * Threading model: WS event callback runs on the AsyncTCP task on a
    different core; what's safe / unsafe to share with the main loop;
    the wsPendingMask deferral pattern; why cross-task globals need to
    be marked volatile.
  * WiFi/BLE coexistence: do NOT call WiFi.setSleep(false); the BT
    coex layer needs WiFi's sleep windows for BLE slots.
  * ESPAsyncWebServer ordering rules (server.begin() last, server.end()
    doesn't clear handlers, single WS client cap).
  * macOS curl AAAA workaround (curl -4 or --resolve) — saves 5s per
    request when debugging.
  * AP-mode fallback credentials (DecentScale / 12345678 / 192.168.1.1).
  * "When X is broken, check Y" troubleshooting table.
  * Naming conventions (b_, i_, t_, f_ Hungarian-ish prefixes).
  * .gitattributes LF-normalization note for bisect across that commit.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Fact-check on PR decentespresso#55 caught two loose phrasings:

  * "races the OLED draws in loop()" understated the issue. The races
    are against any draws issued from the main-loop task, which
    includes button callbacks and menu/display helpers, not just code
    literally inside loop().

  * "just bool + uint32_t writes" mis-described StopWatch (it has an
    enum + multiple uint32_t fields plus a function pointer). The
    actual safety argument is that each individual field write is
    atomic on ESP32, so start/stop/reset can't tear a reader on the
    main-loop task.

No semantic change to the threading model the doc is describing.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
CLAUDE.md is a living document; future sessions should update it when
they hit a new footgun or workflow shift. Add explicit guidance on
what to add, what to skip, and when to prune, so it doesn't decay
into stale advice.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant