# Contributing to AT Protocol OCaml Thank you for your interest in contributing! This document provides guidelines and instructions for contributing to the AT Protocol OCaml libraries. ## Getting Started ### Prerequisites - OCaml >= 5.1 (5.4 recommended) - opam >= 2.0 - dune >= 3.20 ### Setting Up Development Environment ```bash # Clone the repository git clone https://github.com/gdiazlo/atproto.git cd atproto # Install dependencies opam install . --deps-only --with-test # Build the project dune build # Run tests dune runtest ``` ## Project Structure ``` atproto/ ├── lib/ # Library source code │ ├── api/ # High-level API client │ ├── crypto/ # Cryptographic operations │ ├── effects/ # I/O effect abstractions │ ├── identity/ # DID/Handle resolution │ ├── ipld/ # DAG-CBOR, CIDs, CAR files │ ├── lexicon/ # Schema parsing/validation │ ├── mst/ # Merkle Search Tree │ ├── multibase/ # Base encoding │ ├── repo/ # Repository operations │ ├── sync/ # Firehose and sync │ ├── syntax/ # Identifier parsing │ └── xrpc/ # XRPC client/server ├── test/ # Test suites │ ├── fixtures/ # Test data (atproto-interop-tests) │ └── */ # Per-package tests ├── examples/ # Example applications └── dune-project # Project configuration ``` ## Development Workflow ### Running Tests ```bash # Run all tests dune runtest # Run tests for a specific package dune runtest test/syntax # Run with verbose output dune runtest --force --verbose # Run a specific test file dune exec test/syntax/test_syntax.exe ``` ### Code Formatting We use ocamlformat for consistent code style: ```bash # Format all files dune fmt # Check formatting without modifying dune fmt --preview ``` The project uses the default ocamlformat configuration (see `.ocamlformat`). ### Building Documentation ```bash # Build API documentation dune build @doc # Open in browser open _build/default/_doc/_html/index.html ``` ## Coding Guidelines ### General Principles 1. **Functional first** - Prefer immutable data structures and pure functions 2. **Type safety** - Use the type system to prevent errors at compile time 3. **No regex** - All syntax validation uses hand-written parsers 4. **Effects for I/O** - Use the effects system for all I/O operations ### Module Structure Each package follows a consistent structure: ``` lib/packagename/ ├── dune # Build configuration ├── atproto_packagename.ml # Public interface (re-exports) ├── module1.ml # Implementation ├── module1.mli # Interface (optional but recommended) └── ... ``` ### Code Style ```ocaml (* Use descriptive names *) let validate_handle s = ... (* Document public functions *) (** [of_string s] parses [s] as a handle. Returns [Error msg] if the string is not a valid handle. *) val of_string : string -> (t, string) result (* Prefer Result over exceptions for expected errors *) let parse input = match ... with | Some v -> Ok v | None -> Error "invalid input" (* Use labeled arguments for clarity when appropriate *) let create ~did ~handle ~service_endpoint = ... ``` ### Error Handling - Use `Result` for recoverable errors - Use `Option` for optional values - Reserve exceptions for programming errors (bugs) - Provide descriptive error messages ### Testing - Every module should have corresponding tests - Use the interop test fixtures where applicable - Test edge cases and error conditions - Structure tests with clear descriptions ```ocaml let test_handle_valid () = let cases = ["alice.bsky.social"; "test.example.com"] in List.iter (fun s -> match Handle.of_string s with | Ok _ -> () | Error e -> Alcotest.fail (Printf.sprintf "%s: %s" s e) ) cases let () = Alcotest.run "Handle" [ "parsing", [ Alcotest.test_case "valid handles" `Quick test_handle_valid; Alcotest.test_case "invalid handles" `Quick test_handle_invalid; ]; ] ``` ## Making Changes ### Before You Start 1. Check existing issues to avoid duplicate work 2. For large changes, open an issue first to discuss the approach 3. Make sure you understand the AT Protocol specs at [atproto.com](https://atproto.com/specs) ### Pull Request Process 1. **Fork and branch** - Create a feature branch from `main` ```bash git checkout -b feature/my-feature ``` 2. **Make changes** - Follow the coding guidelines above 3. **Test** - Ensure all tests pass ```bash dune runtest ``` 4. **Format** - Run the formatter ```bash dune fmt ``` 5. **Commit** - Write clear commit messages ``` Add handle resolution via DNS TXT records Implements DNS-based handle resolution as specified in the AT Protocol identity spec. Includes tests using fixtures from atproto-interop-tests. ``` 6. **Push and PR** - Open a pull request with: - Clear description of changes - Reference to related issues - Test coverage for new functionality ### Commit Message Format ``` : ``` Types: - `feat` - New feature - `fix` - Bug fix - `docs` - Documentation only - `test` - Adding or updating tests - `refactor` - Code change that doesn't fix a bug or add a feature - `chore` - Maintenance tasks ## Working with the AT Protocol Spec ### Key Resources - [AT Protocol Specification](https://atproto.com/specs) - [Lexicon Reference](https://atproto.com/specs/lexicon) - [Data Model](https://atproto.com/specs/data-model) - [Repository Spec](https://atproto.com/specs/repository) ### Interop Tests The test fixtures in `test/fixtures/` come from the official [atproto-interop-tests](https://github.com/bluesky-social/atproto-interop-tests) repository. To update fixtures: ```bash cd test/fixtures git pull origin main ``` When implementing new functionality, check if there are relevant fixtures to test against. ## Package-Specific Notes ### atproto-syntax - No regex - all parsing is done with hand-written parsers - Each identifier type has `of_string`, `to_string`, and validation - Follow the exact spec for character sets and lengths ### atproto-crypto - Uses `mirage-crypto-ec` for P-256 - Uses `secp256k1-ml` indirectly via custom K-256 wrapper - Always apply low-S normalization to signatures - did:key encoding must match multicodec spec exactly ### atproto-ipld - DAG-CBOR keys must be sorted by length, then lexicographically - CIDs use SHA-256 and base32lower encoding - Support both CIDv0 and CIDv1 ### atproto-effects - Define effect types for all I/O operations - Keep effect handlers separate from business logic - Test with mock handlers, deploy with real handlers ## Questions? - Open an issue for questions about the codebase - Check the AT Protocol Discord for protocol questions - Review the reference TypeScript implementation for clarification ## License By contributing, you agree that your contributions will be licensed under the MIT License.