jsont
JSON type-safe encoding and decoding using the OCaml jsont library. Use when Claude needs to: define typed JSON codecs for OCaml record types, parse JSON strings to OCaml values, or serialize OCaml values to JSON, or work with nested JSON structures
What this skill does
# Jsont JSON Encoding/Decoding
## Dependencies
```dune
(libraries jsont jsont.bytesrw)
```
## Core Patterns
### Simple Object Codec
Map a JSON object to an OCaml record using `Jsont.Object.map` with `mem` for required fields:
```ocaml
type header = {
message_id : string;
method_ : string;
timestamp : int;
}
let header_codec =
Jsont.Object.map ~kind:"header"
(fun message_id method_ timestamp -> { message_id; method_; timestamp })
|> Jsont.Object.mem "messageId" Jsont.string ~enc:(fun h -> h.message_id)
|> Jsont.Object.mem "method" Jsont.string ~enc:(fun h -> h.method_)
|> Jsont.Object.mem "timestamp" Jsont.int ~enc:(fun h -> h.timestamp)
|> Jsont.Object.finish
```
### Optional Fields
Use `opt_mem` for optional JSON fields. The constructor receives `'a option`:
```ocaml
type config = {
name : string;
timeout : int; (* default if missing *)
}
let config_codec =
Jsont.Object.map ~kind:"config"
(fun name timeout_opt ->
{ name; timeout = Option.value ~default:30 timeout_opt })
|> Jsont.Object.mem "name" Jsont.string ~enc:(fun c -> c.name)
|> Jsont.Object.opt_mem "timeout" Jsont.int ~enc:(fun c -> Some c.timeout)
|> Jsont.Object.finish
```
### Skip Unknown Fields
Use `skip_unknown` before `finish` to ignore extra JSON fields (tolerant parsing):
```ocaml
let tolerant_codec =
Jsont.Object.map ~kind:"data" (fun id -> { id })
|> Jsont.Object.mem "id" Jsont.string ~enc:(fun d -> d.id)
|> Jsont.Object.skip_unknown (* ignore extra fields *)
|> Jsont.Object.finish
```
### Nested Objects
Compose codecs for nested structures:
```ocaml
type request = { header : header; payload : payload }
let request_codec payload_codec =
Jsont.Object.map ~kind:"request" (fun header payload -> { header; payload })
|> Jsont.Object.mem "header" header_codec ~enc:(fun r -> r.header)
|> Jsont.Object.mem "payload" payload_codec ~enc:(fun r -> r.payload)
|> Jsont.Object.finish
```
### Lists
Use `Jsont.list` for JSON arrays:
```ocaml
type response = { items : item list }
let response_codec =
Jsont.Object.map ~kind:"response" (fun items -> { items })
|> Jsont.Object.mem "items" (Jsont.list item_codec) ~enc:(fun r -> r.items)
|> Jsont.Object.finish
```
### String Maps
Use `Jsont.Object.as_string_map` for objects with dynamic keys:
```ocaml
module String_map = Map.Make(String)
(* JSON: {"key1": "value1", "key2": "value2"} *)
let string_map_codec = Jsont.Object.as_string_map Jsont.string
(* JSON: {"group1": [...], "group2": [...]} *)
let groups_codec = Jsont.Object.as_string_map (Jsont.list item_codec)
```
### Empty Object
For payloads that don't carry data:
```ocaml
let empty_payload_codec : unit Jsont.t =
Jsont.Object.map ~kind:"empty" ()
|> Jsont.Object.skip_unknown
|> Jsont.Object.finish
```
### Custom Value Mapping
Use `Jsont.map` to transform between types:
```ocaml
type device_type = Sonos | Meross | Other
let device_from_string =
Jsont.map ~kind:"device_type"
~dec:(function "sonos" -> Sonos | "meross" -> Meross | _ -> Other)
~enc:(function Sonos -> "sonos" | Meross -> "meross" | Other -> "other")
Jsont.string
```
### Polymorphic Decoding with `any`
Handle multiple JSON shapes for backwards compatibility:
```ocaml
(* Device can be string (old format) or object (new format) *)
let device_compat_codec =
Jsont.any ~kind:"device"
~dec_string:device_from_string_codec (* handles "192.168.1.1" *)
~dec_object:device_object_codec (* handles {"ip": "...", "type": "..."} *)
~enc:(fun _ -> device_object_codec) (* always encode as object *)
()
```
### Null Values
Use `Jsont.null` for endpoints returning null:
```ocaml
(* For DELETE endpoints that return null on success *)
match delete http ~sw token endpoint (Jsont.null ()) with
| Ok () -> ...
```
### Generic JSON
Use `Jsont.json` to preserve arbitrary JSON:
```ocaml
type characteristic = {
iid : int;
value : Jsont.json option; (* preserve any JSON value *)
}
let char_codec =
Jsont.Object.map ~kind:"char" (fun iid value -> { iid; value })
|> Jsont.Object.mem "iid" Jsont.int ~enc:(fun c -> c.iid)
|> Jsont.Object.opt_mem "value" Jsont.json ~enc:(fun c -> c.value)
|> Jsont.Object.finish
```
## Encoding and Decoding
Use `Jsont_bytesrw` for string-based encoding/decoding:
```ocaml
(* Decode JSON string to OCaml value *)
let decode codec s = Jsont_bytesrw.decode_string codec s
(* Returns: ('a, Jsont.Error.t) result *)
(* Encode OCaml value to JSON string *)
let encode codec v =
match Jsont_bytesrw.encode_string codec v with
| Ok s -> s
| Error _ -> "{}" (* fallback for encoding errors *)
(* Usage *)
match Jsont_bytesrw.decode_string config_codec json_string with
| Ok config -> (* use config *)
| Error e -> (* handle error *)
match Jsont_bytesrw.encode_string config_codec config with
| Ok json_str -> (* send json_str *)
| Error _ -> (* handle error *)
```
## Common Helpers
Define module-level helpers for cleaner code:
```ocaml
let decode codec s = Jsont_bytesrw.decode_string codec s
let encode codec v =
match Jsont_bytesrw.encode_string codec v with
| Ok s -> s
| Error _ -> ""
```
## Base Types Reference
| OCaml Type | Jsont Codec | JSON Type |
|------------|-------------|-----------|
| `string` | `Jsont.string` | string |
| `int` | `Jsont.int` | number |
| `float` | `Jsont.number` | number |
| `bool` | `Jsont.bool` | boolean |
| `'a list` | `Jsont.list codec` | array |
| `'a option` | `Jsont.option codec` | value or null |
| `unit` | `Jsont.null ()` | null |
| generic | `Jsont.json` | any JSON |
## Good and Bad Examples
### Missing `~kind`
**Bad**: No kind makes error messages unhelpful
```ocaml
let config_codec =
Jsont.Object.map (fun name -> { name }) (* No ~kind *)
|> Jsont.Object.mem "name" Jsont.string ~enc:(fun c -> c.name)
|> Jsont.Object.finish
(* Error: "expected string" - but where? *)
```
**Good**: Descriptive kind for clear errors
```ocaml
let config_codec =
Jsont.Object.map ~kind:"config" (fun name -> { name })
|> Jsont.Object.mem "name" Jsont.string ~enc:(fun c -> c.name)
|> Jsont.Object.finish
(* Error: "config: expected string for member 'name'" *)
```
### Strict vs Tolerant Parsing
**Bad**: Strict parsing breaks when API adds fields
```ocaml
(* API adds "created_at" field, your code breaks *)
let user_codec =
Jsont.Object.map ~kind:"user" (fun id name -> { id; name })
|> Jsont.Object.mem "id" Jsont.int ~enc:(fun u -> u.id)
|> Jsont.Object.mem "name" Jsont.string ~enc:(fun u -> u.name)
|> Jsont.Object.finish (* No skip_unknown! *)
```
**Good**: Tolerant parsing ignores unknown fields
```ocaml
let user_codec =
Jsont.Object.map ~kind:"user" (fun id name -> { id; name })
|> Jsont.Object.mem "id" Jsont.int ~enc:(fun u -> u.id)
|> Jsont.Object.mem "name" Jsont.string ~enc:(fun u -> u.name)
|> Jsont.Object.skip_unknown (* Ignore extra fields *)
|> Jsont.Object.finish
```
### Handling Optional Fields
**Bad**: Nullable field without default causes runtime errors
```ocaml
(* Field missing → decode fails *)
let config_codec =
Jsont.Object.map ~kind:"config" (fun timeout -> { timeout })
|> Jsont.Object.mem "timeout" Jsont.int ~enc:(fun c -> c.timeout)
|> Jsont.Object.finish
```
**Good**: Use `opt_mem` with sensible default
```ocaml
let config_codec =
Jsont.Object.map ~kind:"config"
(fun timeout_opt -> { timeout = Option.value ~default:30 timeout_opt })
|> Jsont.Object.opt_mem "timeout" Jsont.int ~enc:(fun c -> Some c.timeout)
|> Jsont.Object.finish
```
### Codec Composition
**Bad**: Monolithic codec with duplicated patterns
```ocaml
let request_codec =
Jsont.Object.map ~kind:"request"
(fun msg_id method_ ts payload_id payload_data ->
{ header = { message_id = msg_id; method_; timestamp = ts };
payload = { id = payload_id; data = payload_data } })
|> Jsont.Object.mem "messageId" Jsont.string ~enc:(fun r -> r.header.message_id)
|> Jsont.Object.mem "method" Jsont.string ~enc:(fRelated in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.