plugins/ocaml-dev/skills/ocaml/SKILL.md
OCaml development guidance for building robust, type-safe applications. Use when Claude needs to: (1) Write OCaml code following modern best practices, (2) Design module interfaces (.mli files), (3) Handle errors with result types, (4) Work with dune build system, (5) Use common OCaml libraries (eio, fmt, logs, cmdliner, yojson, cohttp-eio), or any other OCaml development tasks
npx skillsauth add avsm/ocaml-claude-marketplace ocamlInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
.mli file first. A clean interface matters more than clever implementation.dune exclusivelydune fmt before committing (uses ocamlformat)eiofmtlogscmdlineryojsoncohttp-eioEvery .mli file starts with a top-level doc comment:
(** User API
This module provides types and functions for interacting with users. *)
Use [function_name arg1 arg2] is ... pattern:
val is_bot : t -> bool
(** [is_bot u] is [true] if [u] is a bot user. *)
For values, describe what they represent:
type id = string
(** A user identifier. *)
For modules with a central type t, provide these functions where applicable:
| Function | Purpose |
|----------|---------|
| val v : ... -> t | Pure smart constructor (no I/O) |
| val create : ... -> (t, Error.t) result | Constructor with side-effects |
| val pp : t Fmt.t | Pretty-printer for logging/debugging |
| val equal : t -> t -> bool | Structural equality |
| val compare : t -> t -> int | Comparison for sorting |
| val of_json : Yojson.Safe.t -> (t, string) result | Parse from JSON |
| val to_json : t -> Yojson.Safe.t | Serialize to JSON |
| val validate : t -> (t, string) result | Validate data integrity |
Keep types abstract (type t) when possible. Expose smart constructors and accessors instead of record fields to maintain invariants.
Use result type for recoverable errors. Reserve exceptions for programming errors (e.g., Invalid_argument).
Define a comprehensive error type in lib/error.ml:
(* In lib/error.mli *)
type t = [
| `Api of string * Yojson.Safe.t
| `Json_parse of string
| `Network of string
| `Msg of string
]
val pp : t Fmt.t
let err_api code fields = Error (`Api (code, fields))
let err_parse msg = Error (`Json_parse msg)
let find_user_id json =
match Yojson.Safe.Util.find_opt "id" json with
| Some (`String id) -> Ok id
| Some _ -> err_parse "Expected string for user ID"
| None -> err_parse "Missing user ID"
try ... with _ -> .... Match specific exceptions.Fmt.failwith:let tls_config =
match Tls.Config.client ~authenticator () with
| Ok config -> config
| Error (`Msg msg) -> Fmt.failwith "Failed to create TLS config: %s" msg
match/if signals need for refactoring.bin/, lib/ui/).Use the logs library with per-module log sources:
let log_src = Logs.Src.create "project_name.module_name"
module Log = (val Logs.src_log log_src : Logs.LOG)
| Level | Use Case |
|-------|----------|
| Log.app | Messages always shown to user (startup) |
| Log.err | Handled but critical errors |
| Log.warn | Potential issues, operation continues |
| Log.info | Informational state messages |
| Log.debug | Verbose debugging details |
Log.info (fun m ->
m "Received event: %s" event_type
~tags:(Logs.Tag.add "channel_id" channel_id Logs.Tag.empty))
| Element | Convention | Example |
|---------|------------|---------|
| Files | lowercase_underscores | user_profile.ml |
| Modules | lowercase_underscores | user_profile |
| Primary type | t | type t |
| Identifiers | id | type id = string |
| Values | short_descriptive | find_user, create_channel |
Use labels only when they clarify meaning. Avoid ~f and ~x.
For bin/ applications using cmdliner:
bin/common.mlrun function that initializes the main loop and environment (e.g., Eio loop)Follow Conventional Commits:
Format: type(scope): subject
| Type | Purpose |
|------|---------|
| feat | New feature |
| fix | Bug fix |
| docs | Documentation |
| style | Formatting |
| refactor | Code restructuring |
| test | Tests |
| chore | Maintenance |
Examples:
feat(api): add support for file uploadsfix(ui): correct channel list rendering bugtest(user): add tests for user profile updatestools
Working with the OxCaml extensions to OCaml. Use when the oxcaml compiler is available and you need high-performance, unboxing, stack allocation, data-race-free parallelism
development
Creating OCaml library tutorials using .mld documentation format with MDX executable examples. Use when discussing tutorials, documentation, .mld files, MDX, or interactive documentation.
development
Testing strategies for OCaml libraries. Use when discussing tests, alcotest, eio mocks, test structure, or test-driven development in OCaml projects.
development
Security hardening for OCaml libraries through systematic vulnerability research. Use when Claude needs to: (1) Research CVEs in similar implementations (C, Rust, Go, Python) and add regression tests, (2) Add fuzz tests for parsers and encoders, (3) Audit integer handling and buffer operations, (4) Test boundary conditions and malformed input, (5) Review cryptographic usage, (6) Add defensive checks against common vulnerability classes