Skip to content

Commit bd9c95d

Browse files
committed
docs: add document for AI agents (AGENTS.md)
1 parent 8bf6dd2 commit bd9c95d

File tree

1 file changed

+105
-0
lines changed

1 file changed

+105
-0
lines changed

AGENTS.md

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# Agents
2+
3+
This document helps AI agents work effectively in this codebase. It explains the philosophy, patterns, and pitfalls behind the code, so you can make good decisions on any task, not just scenarios explicitly covered. Apply these principles while reading the code for specifics.
4+
5+
## Philosophy
6+
7+
This is a minimal, idiomatic WebSocket library. Simplicity is a feature. Before adding code, consider whether it's necessary. Before adding a dependency, don't; tests requiring external packages are isolated in `internal/thirdparty`.
8+
9+
## Research
10+
11+
**Read the issue carefully.** Before designing a solution, verify you understand what's actually being requested. Restate the problem in your own words. A solution to the wrong problem wastes everyone's time.
12+
13+
**Understand the protocol first.** Code comments reference RFC 6455 (WebSocket), RFC 7692 (compression), and RFC 8441 (HTTP/2). When behavior seems odd, check the RFC section cited nearby.
14+
15+
**Trace from public API inward.** Start with `Accept` (server) or `Dial` (client), then follow to `Conn`, then to `Reader`/`Writer`. The internal structure follows these paths.
16+
17+
**Read tests for intent.** Tests often reveal why code exists. The autobahn-testsuite (`autobahn_test.go`) validates protocol compliance; if you're unsure whether behavior is correct, that's the authority.
18+
19+
**Check both platforms.** Native Go files have `//go:build !js`. WASM lives in `ws_js.go` (imports `syscall/js`). They have the same API but different implementations. WASM wraps browser APIs and cannot control framing, compression, or masking, so don't try to implement those features there.
20+
21+
**Search exhaustively when modifying patterns.** When changing how something is done in multiple places, grep for all instances. Missing one creates inconsistent behavior.
22+
23+
## Making Changes
24+
25+
**Every change needs a reason.** Don't reword comments, rename variables, or restructure code without justification. If you can't articulate why a change improves things, don't make it.
26+
27+
**Understand before changing.** Research the code you're modifying. Trace the call paths, read the tests, check both platforms. A change with good intentions but incomplete understanding can break things in ways you won't notice.
28+
29+
**Ask for clarification rather than assuming.** If requirements are ambiguous or you're unsure how something should work, stop and ask. A wrong assumption can waste more time than a quick question.
30+
31+
**Iterate, don't pivot.** When feedback identifies a problem, fix that problem. Don't discard everything and start over with a different approach. Preserve what's working; adjust what isn't.
32+
33+
**Verify examples work.** Trace through usage examples as if writing real code. If an example wouldn't compile, the design is wrong.
34+
35+
**Don't delete existing comments.** Comments that explain non-obvious behavior preserve important context about why code works a certain way. If a comment seems wrong, verify before removing.
36+
37+
**Check if it already exists.** Before proposing new API, read existing function signatures, return values, and doc comments. The feature might already be there.
38+
39+
**Ask: does this need to exist?** The library stays small by saying no. A feature that solves one user's problem but complicates the API for everyone is not worth it.
40+
41+
**Ask: is this the user's job or the library's job?** The library handles protocol correctness. Application-level concerns (reconnection, auth, message routing) belong in user code.
42+
43+
**Ask: what breaks if I'm wrong?** Context cancellation closes connections. Pooled objects must be returned. Locks must respect context. These invariants exist because violating them causes subtle bugs.
44+
45+
## Code Style
46+
47+
Follow Go conventions: [Effective Go](https://go.dev/doc/effective_go), [Go Code Review Comments](https://go.dev/wiki/CodeReviewComments), and [Go Proverbs](https://go-proverbs.github.io/). Be concise, declarative, and factual.
48+
49+
Never use emdash. Use commas, semicolons, or separate sentences.
50+
51+
**Doc comments** start with the name and state what it does. Put useful information where users make decisions (usually the constructor, not methods).
52+
53+
**Inline comments** are terse. Prefer end-of-line when short enough.
54+
55+
**Explain why, not what.** The code shows what it does; comments should explain reasoning, non-obvious decisions, or edge cases.
56+
57+
**Wrap comments** at ~80 characters, continuing naturally at word boundaries. Don't put each sentence on its own line.
58+
59+
**Avoid:**
60+
61+
- Tautologies and redundant explanations the code already conveys
62+
- Filler phrases: "Note that", "This is because", "It should be noted"
63+
- Hedging: "basically", "actually", "really"
64+
65+
## Key Invariants
66+
67+
**Always read from connections.** Control frames (ping, pong, close) arrive on the read path. A connection that never reads will miss them and misbehave. `CloseRead` exists for write-only patterns.
68+
69+
**Pooled objects must be returned.** `flate.Writer` is ~1.2MB. Leaking them causes memory growth. Follow `get*()` / `put*()` patterns; return on all paths including errors.
70+
71+
**Locks must respect context.** The `mu` type in `conn.go` unblocks when context cancels or connection closes. Using `sync.Mutex` for user-facing operations would block forever on stuck connections.
72+
73+
**Reads and writes are independent.** They have separate locks (`readMu`, `writeFrameMu`) and can happen concurrently. Don't create unnecessary coupling between them.
74+
75+
**Masking is asymmetric.** Clients mask payloads; servers don't. The mask is applied into the bufio.Writer buffer, not in-place on source bytes.
76+
77+
## Testing
78+
79+
**Protocol compliance:** run autobahn tests with `AUTOBAHN=1 go test`. Some tests are intentionally skipped (UTF-8 validation adds overhead without value; `requestMaxWindowBits` is unimplemented due to `compress/flate` limitations).
80+
81+
**Frame-level correctness:** compare wire bytes. When two implementations disagree, capture the bytes and check against the RFC.
82+
83+
**WASM compatibility:** API changes need both implementations. Test that method signatures match.
84+
85+
**Test style:** prefer table-driven tests and simple want/got comparison.
86+
87+
## Commits and PRs
88+
89+
Use conventional commits: `type(scope): description`. Scope is optional but include it when changes are constrained to a single file or directory.
90+
91+
**Choose precise verbs:** `add` (new functionality), `fix` (broken behavior), `prevent` (undesirable state), `allow` (enable action), `handle` (edge cases), `improve` (performance/quality), `use` (change approach), `skip` (bypass), `remove` (delete), `rewrite` (substantial rework).
92+
93+
**Commit messages explain why.** State what was wrong with previous behavior, why it mattered, and why this solution was chosen. One to three sentences. Keep the tone neutral; don't editorialize.
94+
95+
**PR descriptions are for humans.** Don't fill out a template with "Summary", "Background", "Changes" headers. Don't restate the diff. Explain what reviewers can't see: the why, alternatives considered, and tradeoffs made. Show evidence (logs, benchmarks, screenshots). Be explicit about what the PR doesn't do.
96+
97+
**Link issues:** `Fixes #123` (PR resolves it), `Refs #123` (related), `Updates #123` (partial progress).
98+
99+
## RFC References
100+
101+
- RFC 6455: The WebSocket Protocol
102+
- RFC 7692: Compression Extensions for WebSocket (permessage-deflate)
103+
- RFC 8441: Bootstrapping WebSockets with HTTP/2
104+
105+
Section numbers in code comments refer to these RFCs.

0 commit comments

Comments
 (0)