{"id":13774071,"url":"https://github.com/extism/ocaml-sdk","last_synced_at":"2025-07-04T12:04:38.544Z","repository":{"id":194682894,"uuid":"691134566","full_name":"extism/ocaml-sdk","owner":"extism","description":"Extism OCaml Host SDK ","archived":false,"fork":false,"pushed_at":"2024-05-22T22:47:07.000Z","size":3248,"stargazers_count":12,"open_issues_count":1,"forks_count":0,"subscribers_count":5,"default_branch":"main","last_synced_at":"2024-05-22T23:41:58.884Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"OCaml","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/extism.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-09-13T15:08:36.000Z","updated_at":"2024-06-13T06:51:33.323Z","dependencies_parsed_at":"2023-09-14T16:59:15.288Z","dependency_job_id":"3d95366d-c7da-481a-9849-c593bf38ed1f","html_url":"https://github.com/extism/ocaml-sdk","commit_stats":null,"previous_names":["extism/ocaml-sdk"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/extism/ocaml-sdk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/extism%2Focaml-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/extism%2Focaml-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/extism%2Focaml-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/extism%2Focaml-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/extism","download_url":"https://codeload.github.com/extism/ocaml-sdk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/extism%2Focaml-sdk/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263507812,"owners_count":23477401,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-03T17:01:23.420Z","updated_at":"2025-07-04T12:04:38.498Z","avatar_url":"https://github.com/extism.png","language":"OCaml","funding_links":[],"categories":["\u003ca name=\"extism\"\u003e\u003c/a\u003e[Extism](https://github.com/extism/extism) \u003csup\u003e[top⇈](#contents)\u003c/sup\u003e"],"sub_categories":[],"readme":"# Extism OCaml Host SDK\n\nThis repo contains the OCaml package for integrating with the [Extism](https://extism.org/) runtime.\n\n\u003e **Note**: If you're unsure what Extism is or what an SDK is see our homepage: [https://extism.org](https://extism.org).\n\n## Documentation\n\nDocumentation is available at [https://extism.github.io/ocaml-sdk](https://extism.github.io/ocaml-sdk)\n\n## Installation\n\n### Install the Extism Runtime Dependency\n\nFor this library, you first need to install the Extism Runtime. You can [download the shared object directly from a release](https://github.com/extism/extism/releases) or use the [Extism CLI](https://github.com/extism/cli) to install it.\n\n### Add the library to dune\n\nThen add `extism` to your [dune](https://dune.build) depdendencies:\n\n```\n  (libraries extism)\n```\n\nIf you're generating an opam file using dune then add `extism` to your `dune-project` package `depends` section:\n\n```\n(package\n (depends\n  (extism (\u003e= 1.1.0))))\n```\n\nInstalling the `extism` package on opam will also install the `extism-call` executable, which can be used\nto execute Extism plugins.\n\n## Getting Started\n\nThis guide should walk you through some of the concepts in Extism and the OCaml bindings.\n\n### Creating A Plug-in\n\nThe primary concept in Extism is the [plug-in](https://extism.org/docs/concepts/plug-in). You can think of a plug-in as a code module stored in a `.wasm` file.\n\nSince you may not have an Extism plug-in on hand to test, let's load a demo plug-in from the web:\n\n```ocaml\nopen Extism\n\nlet wasm = Manifest.Wasm.url \"https://github.com/extism/plugins/releases/latest/download/count_vowels.wasm\"\nlet manifest = Manifest.create [wasm]\nlet plugin = Plugin.of_manifest_exn manifest\n```\n\n\u003e **Note**: See [the Manifest docs](https://extism.github.io/ocaml-sdk/extism-manifest/Extism_manifest/index.html) as it has a rich schema and a lot of options.\n\n### Calling A Plug-in's Exports\n\nThis plug-in was written in Rust and it does one thing, it counts vowels in a string. As such, it exposes one \"export\" function: `count_vowels`. We can call exports using [Extism.Plugin.call](https://extism.github.io/ocaml-sdk/extism/Extism/Plugin/index.html#val-call):\n\n\u003c!-- $MDX skip --\u003e\n```ocaml\n# Plugin.call_string_exn plugin ~name:\"count_vowels\" \"Hello, world!\";;\n- : string = \"{\\\"count\\\":3,\\\"total\\\":3,\\\"vowels\\\":\\\"aeiouAEIOU\\\"}\"\n```\n\nAll exports have a simple interface of bytes-in and bytes-out. This plug-in happens to take a string and return a JSON encoded string with a report of results.\n\nThis library also allows for calls to be typed, when the input and output types are not strings. Instead of getting the output as a JSON encoded string, we can\nconvert it directly to `Yojson.Safe.t`:\n\n\u003c!-- $MDX skip --\u003e\n```ocaml\n# Plugin.call_exn Type.string Type.json plugin ~name:\"count_vowels\" \"Hello, world!\";;\n- : Yojson.Safe.t =\n`Assoc\n  [(\"count\", `Int 3); (\"total\", `Int 6); (\"vowels\", `String \"aeiouAEIOU\")]\n```\n\nSee [Extism.Type.S](https://extism.github.io/ocaml-sdk/extism/Extism/Type/module-type-S/index.html) to define your own input/output types.\n\n### Typed Plugins\n\nPlug-ins can also use pre-defined functions using `Plugin.Typed`:\n\n```ocaml\nmodule Example = struct\n  include Plugin.Typed.Init ()\n\n  let count_vowels = exn @@ fn \"count_vowels\" Type.string Type.json\nend\n```\n\nThis can then be initialized using an existing `Plugin.t`:\n\n```ocaml\nlet example = Example.of_plugin_exn plugin in\nlet res = Example.count_vowels example \"this is a test\" in\nprint_endline (Yojson.Safe.to_string res)\n```\n\n### Plug-in State\n\nPlug-ins may be stateful or stateless. Plug-ins can maintain state b/w calls by the use of variables. Our count vowels plug-in remembers the total number of vowels it's ever counted in the \"total\" key in the result. You can see this by making subsequent calls to the export:\n\n\u003c!-- $MDX skip --\u003e\n```ocaml\n# Plugin.call_string_exn plugin ~name:\"count_vowels\" \"Hello, world!\" |\u003e print_endline;;\n{\"count\":3,\"total\":9,\"vowels\":\"aeiouAEIOU\"}\n- : unit = ()\n# Plugin.call_string_exn plugin ~name:\"count_vowels\" \"Hello, world!\" |\u003e print_endline;;\n{\"count\":3,\"total\":12,\"vowels\":\"aeiouAEIOU\"}\n- : unit = ()\n```\n\nThese variables will persist until this plug-in is freed or you initialize a new one.\n\n### Configuration\n\nPlug-ins may optionally take a configuration object. This is a static way to configure the plug-in. Our count-vowels plugin takes an optional configuration to change out which characters are considered vowels. Example:\n\n\u003c!-- $MDX skip --\u003e\n```ocaml\n# let manifest = Manifest.create [wasm];;\nval manifest : Extism_manifest.t =\n  {Extism.Manifest.wasm =\n    [Extism.Manifest.Wasm.Url\n      {Extism.Manifest.Wasm.url =\n        \"https://github.com/extism/plugins/releases/latest/download/count_vowels.wasm\";\n       headers = None; meth = None; name = None; hash = None}];\n   memory = None; config = None; allowed_hosts = None; allowed_paths = None;\n   timeout_ms = None}\n\n# let plugin = Plugin.of_manifest_exn manifest;;\nval plugin : Plugin.t = \u003cabstr\u003e\n# Plugin.call_string_exn plugin ~name:\"count_vowels\" \"Yellow, world!\" |\u003e print_endline;;\n{\"count\":3,\"total\":3,\"vowels\":\"aeiouAEIOU\"}\n- : unit = ()\n\n# let plugin = Plugin.of_manifest_exn @@ Manifest.with_config [\"vowels\", Some \"aeiouAEIOUY\"] manifest;;\nval plugin : Plugin.t = \u003cabstr\u003e\n# Plugin.call_string_exn plugin ~name:\"count_vowels\" \"Yellow, world!\" |\u003e print_endline;;\n{\"count\":4,\"total\":4,\"vowels\":\"aeiouAEIOUY\"}\n- : unit = ()\n```\n\n### Host Functions\n\nLet's extend our count-vowels example a little bit: Instead of storing the `total` in an ephemeral plug-in var, let's store it in a persistent key-value store!\n\nWasm can't use our KV store on it's own. This is where [Host Functions](https://extism.org/docs/concepts/host-functions) come in.\n\n[Host functions](https://extism.org/docs/concepts/host-functions) allow us to grant new capabilities to our plug-ins from our application. They are simply some OCaml functions you write which can be passed down and invoked from any language inside the plug-in.\n\nLet's load the manifest like usual but load up this `count_vowels_kvstore` plug-in:\n\n\u003c!-- $MDX file=examples/kv.ml,part=hostFnIntro --\u003e\n```ocaml\nopen Extism\n\nlet url =\n  \"https://github.com/extism/plugins/releases/latest/download/count_vowels_kvstore.wasm\"\n\nlet wasm = Manifest.Wasm.url url\nlet manifest = Manifest.create [ wasm ]\n```\n\n\u003e *Note*: The source code for this is [here](https://github.com/extism/plugins/blob/main/count_vowels_kvstore/src/lib.rs) and is written in rust, but it could be written in any of our PDK languages.\n\nUnlike our previous plug-in, this plug-in expects you to provide host functions that satisfy our its import interface for a KV store.\n\nUsing [Extism.Function](https://extism.github.io/ocaml-sdk/extism/Extism/Function/index.html) we can define a host function that can be called from the guest plug-in. In this example we will create a function to help us load plugins and setup the host functions.\n\nWe want to expose two functions to our plugin (in OCaml types): `val kv_write: string -\u003e string -\u003e unit` which writes a bytes value to a key and `val kv_read: string -\u003e string` which reads the bytes at the given `key`.\n\n\u003c!-- $MDX file=examples/kv.ml,part=hostFnDef --\u003e\n```ocaml\nlet make_kv_plugin () =\n  (* pretend this is Redis or something :) *)\n  let kv_store = Hashtbl.create 8 in\n\n  let kv_read =\n    let open Val_type in\n    Function.create \"kv_read\" ~params:[ ptr ] ~results:[ ptr ] ~user_data:()\n    @@ fun plugin () -\u003e\n    let key = Host_function.input_string plugin in\n    Printf.printf \"Reading from key=%s\\n\" key;\n    let value =\n      try Hashtbl.find kv_store key\n      with Not_found -\u003e String.init 4 (fun _ -\u003e char_of_int 0)\n    in\n    Host_function.output_string plugin value\n  in\n\n  let kv_write =\n    let open Val_type in\n    Function.create \"kv_write\" ~params:[ ptr; ptr ] ~results:[] ~user_data:()\n    @@ fun plugin () -\u003e\n    let key = Host_function.input_string ~index:0 plugin in\n    let value = Host_function.input_string ~index:1 plugin in\n    Printf.printf \"Write value=%s to key=%s\\n\" value key;\n    Hashtbl.replace kv_store key value\n  in\n\n  (* Create a plugin from the manifest with the kv host functions *)\n  Plugin.of_manifest_exn ~functions:[ kv_read; kv_write ] ~wasi:true manifest\n```\n\n\u003e *Note*: In order to write host functions you should get familiar with the methods on the [Extism.Host_function](https://extism.github.io/ocaml-sdk/extism/Extism/Host_function/index.html) module.\n\n\nNow we can invoke the event:\n\n\u003c!-- $MDX skip,env=host-functions --\u003e\n```ocaml\n# let plugin = make_kv_plugin ();;\nval plugin : Plugin.t = \u003cabstr\u003e\n# Extism.Plugin.call_string_exn plugin ~name:\"count_vowels\" \"Hello, world\" |\u003e print_endline;;\nReading from key=count-vowels\nWrite value=^C^@^@^@ to key=count-vowels\n{\"count\":3,\"total\":3,\"vowels\":\"aeiouAEIOU\"}\n- : unit = ()\n# Extism.Plugin.call_string_exn plugin ~name:\"count_vowels\" \"Hello, world\" |\u003e print_endline;;\nReading from key=count-vowels\nWrite value=^F^@^@^@ to key=count-vowels\n{\"count\":3,\"total\":6,\"vowels\":\"aeiouAEIOU\"}\n- : unit = ()\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fextism%2Focaml-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fextism%2Focaml-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fextism%2Focaml-sdk/lists"}