atproto libraries implementation in ocaml
1# Contributing to AT Protocol OCaml
2
3Thank you for your interest in contributing! This document provides guidelines and instructions for contributing to the AT Protocol OCaml libraries.
4
5## Getting Started
6
7### Prerequisites
8
9- OCaml >= 5.1 (5.4 recommended)
10- opam >= 2.0
11- dune >= 3.20
12
13### Setting Up Development Environment
14
15```bash
16# Clone the repository
17git clone https://github.com/gdiazlo/atproto.git
18cd atproto
19
20# Install dependencies
21opam install . --deps-only --with-test
22
23# Build the project
24dune build
25
26# Run tests
27dune runtest
28```
29
30## Project Structure
31
32```
33atproto/
34├── lib/ # Library source code
35│ ├── api/ # High-level API client
36│ ├── crypto/ # Cryptographic operations
37│ ├── effects/ # I/O effect abstractions
38│ ├── identity/ # DID/Handle resolution
39│ ├── ipld/ # DAG-CBOR, CIDs, CAR files
40│ ├── lexicon/ # Schema parsing/validation
41│ ├── mst/ # Merkle Search Tree
42│ ├── multibase/ # Base encoding
43│ ├── repo/ # Repository operations
44│ ├── sync/ # Firehose and sync
45│ ├── syntax/ # Identifier parsing
46│ └── xrpc/ # XRPC client/server
47├── test/ # Test suites
48│ ├── fixtures/ # Test data (atproto-interop-tests)
49│ └── */ # Per-package tests
50├── examples/ # Example applications
51└── dune-project # Project configuration
52```
53
54## Development Workflow
55
56### Running Tests
57
58```bash
59# Run all tests
60dune runtest
61
62# Run tests for a specific package
63dune runtest test/syntax
64
65# Run with verbose output
66dune runtest --force --verbose
67
68# Run a specific test file
69dune exec test/syntax/test_syntax.exe
70```
71
72### Code Formatting
73
74We use ocamlformat for consistent code style:
75
76```bash
77# Format all files
78dune fmt
79
80# Check formatting without modifying
81dune fmt --preview
82```
83
84The project uses the default ocamlformat configuration (see `.ocamlformat`).
85
86### Building Documentation
87
88```bash
89# Build API documentation
90dune build @doc
91
92# Open in browser
93open _build/default/_doc/_html/index.html
94```
95
96## Coding Guidelines
97
98### General Principles
99
1001. **Functional first** - Prefer immutable data structures and pure functions
1012. **Type safety** - Use the type system to prevent errors at compile time
1023. **No regex** - All syntax validation uses hand-written parsers
1034. **Effects for I/O** - Use the effects system for all I/O operations
104
105### Module Structure
106
107Each package follows a consistent structure:
108
109```
110lib/packagename/
111├── dune # Build configuration
112├── atproto_packagename.ml # Public interface (re-exports)
113├── module1.ml # Implementation
114├── module1.mli # Interface (optional but recommended)
115└── ...
116```
117
118### Code Style
119
120```ocaml
121(* Use descriptive names *)
122let validate_handle s = ...
123
124(* Document public functions *)
125(** [of_string s] parses [s] as a handle.
126 Returns [Error msg] if the string is not a valid handle. *)
127val of_string : string -> (t, string) result
128
129(* Prefer Result over exceptions for expected errors *)
130let parse input =
131 match ... with
132 | Some v -> Ok v
133 | None -> Error "invalid input"
134
135(* Use labeled arguments for clarity when appropriate *)
136let create ~did ~handle ~service_endpoint = ...
137```
138
139### Error Handling
140
141- Use `Result` for recoverable errors
142- Use `Option` for optional values
143- Reserve exceptions for programming errors (bugs)
144- Provide descriptive error messages
145
146### Testing
147
148- Every module should have corresponding tests
149- Use the interop test fixtures where applicable
150- Test edge cases and error conditions
151- Structure tests with clear descriptions
152
153```ocaml
154let test_handle_valid () =
155 let cases = ["alice.bsky.social"; "test.example.com"] in
156 List.iter (fun s ->
157 match Handle.of_string s with
158 | Ok _ -> ()
159 | Error e -> Alcotest.fail (Printf.sprintf "%s: %s" s e)
160 ) cases
161
162let () =
163 Alcotest.run "Handle" [
164 "parsing", [
165 Alcotest.test_case "valid handles" `Quick test_handle_valid;
166 Alcotest.test_case "invalid handles" `Quick test_handle_invalid;
167 ];
168 ]
169```
170
171## Making Changes
172
173### Before You Start
174
1751. Check existing issues to avoid duplicate work
1762. For large changes, open an issue first to discuss the approach
1773. Make sure you understand the AT Protocol specs at [atproto.com](https://atproto.com/specs)
178
179### Pull Request Process
180
1811. **Fork and branch** - Create a feature branch from `main`
182 ```bash
183 git checkout -b feature/my-feature
184 ```
185
1862. **Make changes** - Follow the coding guidelines above
187
1883. **Test** - Ensure all tests pass
189 ```bash
190 dune runtest
191 ```
192
1934. **Format** - Run the formatter
194 ```bash
195 dune fmt
196 ```
197
1985. **Commit** - Write clear commit messages
199 ```
200 Add handle resolution via DNS TXT records
201
202 Implements DNS-based handle resolution as specified in
203 the AT Protocol identity spec. Includes tests using
204 fixtures from atproto-interop-tests.
205 ```
206
2076. **Push and PR** - Open a pull request with:
208 - Clear description of changes
209 - Reference to related issues
210 - Test coverage for new functionality
211
212### Commit Message Format
213
214```
215<type>: <short summary>
216
217<detailed description if needed>
218
219<references>
220```
221
222Types:
223- `feat` - New feature
224- `fix` - Bug fix
225- `docs` - Documentation only
226- `test` - Adding or updating tests
227- `refactor` - Code change that doesn't fix a bug or add a feature
228- `chore` - Maintenance tasks
229
230## Working with the AT Protocol Spec
231
232### Key Resources
233
234- [AT Protocol Specification](https://atproto.com/specs)
235- [Lexicon Reference](https://atproto.com/specs/lexicon)
236- [Data Model](https://atproto.com/specs/data-model)
237- [Repository Spec](https://atproto.com/specs/repository)
238
239### Interop Tests
240
241The test fixtures in `test/fixtures/` come from the official
242[atproto-interop-tests](https://github.com/bluesky-social/atproto-interop-tests) repository.
243
244To update fixtures:
245
246```bash
247cd test/fixtures
248git pull origin main
249```
250
251When implementing new functionality, check if there are relevant fixtures to test against.
252
253## Package-Specific Notes
254
255### atproto-syntax
256
257- No regex - all parsing is done with hand-written parsers
258- Each identifier type has `of_string`, `to_string`, and validation
259- Follow the exact spec for character sets and lengths
260
261### atproto-crypto
262
263- Uses `mirage-crypto-ec` for P-256
264- Uses `secp256k1-ml` indirectly via custom K-256 wrapper
265- Always apply low-S normalization to signatures
266- did:key encoding must match multicodec spec exactly
267
268### atproto-ipld
269
270- DAG-CBOR keys must be sorted by length, then lexicographically
271- CIDs use SHA-256 and base32lower encoding
272- Support both CIDv0 and CIDv1
273
274### atproto-effects
275
276- Define effect types for all I/O operations
277- Keep effect handlers separate from business logic
278- Test with mock handlers, deploy with real handlers
279
280## Questions?
281
282- Open an issue for questions about the codebase
283- Check the AT Protocol Discord for protocol questions
284- Review the reference TypeScript implementation for clarification
285
286## License
287
288By contributing, you agree that your contributions will be licensed under the MIT License.