anthropic-clj is a Clojure wrapper over the official Anthropic Java SDK.
Request maps go in, response maps come back.
Messages, model listing, and most examples here call the live Anthropic API and are billed by Anthropic. Do not put live calls in unit tests. Use the existing unit-test style for request and response translation tests. Keep live calls in an explicit integration suite.
Leiningen:
[net.clojars.savya/anthropic-clj "0.11.1"]
tools.deps:
net.clojars.savya/anthropic-clj {:mvn/version "0.11.1"}
Version 0.11.1 pins com.anthropic/anthropic-java 2.48.0.
(require '[anthropic.core :as anthropic])
(def client (anthropic/client))
With no arguments, client uses the official SDK's environment lookup. For the
direct Anthropic API, set ANTHROPIC_API_KEY.
You can also pass explicit options:
(def client
(anthropic/client
{:api-key "sk-ant-..."
:base-url "https://api.anthropic.com"
:timeout-ms 30000
:max-retries 2}))
Supported client option keys:
:api-key:auth-token:base-url:timeout-ms:max-retriesThe wrapper sets only the keys that you supply on the SDK builder.
(def response
(anthropic/create-message
client
{:model "claude-opus-4-8"
:max-tokens 1024
:system "You are concise."
:messages [{:role :user :content "Name three primary colors."}]}))
(:role response)
;; => :assistant
(:content response)
;; => [{:type :text :text "Red, blue, yellow."}]
(-> response :content first :text)
;; => "Red, blue, yellow."
create-message takes a request map and returns a response map. The default
:model is "claude-opus-4-8" and the default :max-tokens is 1024.
Common request keys:
:model:max-tokens:system:messages:tools:temperature:top-p:top-k:stop-sequences:tool-choice:thinking:metadata:service-tier:container:inference-geo:user-profile-id:cache-control:response-format:effortResponse maps include:
:id:model:role:stop-reason:content:usage:container when present:stop-sequence when present:stop-details when present:parsed when the request includes :response-formatThere is no top-level :text convenience key. Read text from text content
blocks:
(def text
(->> (:content response)
(filter #(= :text (:type %)))
first
:text))
:usage always includes :input-tokens and :output-tokens. The wrapper adds
newer usage keys when the API reports them, such as :cache-creation-input-tokens,
:cache-read-input-tokens, :server-tool-use, :service-tier,
:cache-creation, :inference-geo, and :output-tokens-details.
The wrapper normalizes API and I/O failures from the SDK to ex-info.
API failures:
(try
(anthropic/create-message client {:messages [{:role :user :content "hi"}]})
(catch clojure.lang.ExceptionInfo e
(ex-data e)))
;; => {:anthropic/error :api-error
;; :status 429
;; :error-type :rate-limit}
The wrapper keeps the original SDK exception as (ex-cause e).
:error-type can be:
:bad-request:unauthorized:permission-denied:not-found:unprocessable-entity:rate-limit:internal-server:unexpected-status:api-errorI/O failures carry:
{:anthropic/error :io-error}
Request-shaping errors thrown by the wrapper also use ex-info and
:anthropic/error, for example :unsupported-content-block,
:unsupported-server-tool, :unsupported-tool-search-variant,
:unsupported-tool-choice, :unsupported-thinking-type, :no-tool-fn, or
:max-iterations-exceeded.
Other SDK exceptions can pass through unchanged.
Model helper functions call the live API.
(anthropic/list-models client)
;; => [{:id "claude-opus-4-8"
;; :display-name "Claude Opus 4.8"
;; :created-at "2026-..."
;; :max-input-tokens 200000
;; :max-tokens 64000} ...]
(anthropic/get-model client "claude-opus-4-8")
;; => {:id "claude-opus-4-8" :display-name "Claude Opus 4.8" ...}
list-models follows pages automatically and returns a vector.
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |