A client that talks to a remote bsdkrund daemon's GraphQL API directly —
java.net.http.HttpClient for queries/mutations, its built-in
java.net.http.WebSocket speaking graphql-transport-ws for subscriptions
— instead of shelling out to a local bsdkrun binary the way
bsdkrun.sandbox does.
The wire contract (URL/header shape, error mapping, subscription protocol,
field names) is locked to match the other bsdkrun SDKs
(TypeScript/Python/Ruby/Elixir/Gleam) and the web frontend's
web/src/lib/graphql.ts — see that file for the reference implementation
this one mirrors. Unlike every other SDK here, this one needs no
hand-rolled WebSocket framing: java.net.http.WebSocket is a core JDK API
(Java 11+).
A client is a plain map, matching every other namespace's convention —
{:url ... :token ... :http-client ... :ws-state (atom ...)}. Build one
with new-client or client-from-env; every function below takes it
first.
Example:
(require '[bsdkrun.client :as client])
(def c (client/client-from-env))
(doseq [m (client/list-machines c)] (println (:id m)))
(def result (client/exec! c "abc123" ["uname" "-a"]))
(println (String. (:output result)))
A client that talks to a remote `bsdkrund` daemon's GraphQL API directly —
`java.net.http.HttpClient` for queries/mutations, its built-in
`java.net.http.WebSocket` speaking `graphql-transport-ws` for subscriptions
— instead of shelling out to a local `bsdkrun` binary the way
`bsdkrun.sandbox` does.
The wire contract (URL/header shape, error mapping, subscription protocol,
field names) is locked to match the other bsdkrun SDKs
(TypeScript/Python/Ruby/Elixir/Gleam) and the web frontend's
`web/src/lib/graphql.ts` — see that file for the reference implementation
this one mirrors. Unlike every other SDK here, this one needs no
hand-rolled WebSocket framing: `java.net.http.WebSocket` is a core JDK API
(Java 11+).
A `client` is a plain map, matching every other namespace's convention —
`{:url ... :token ... :http-client ... :ws-state (atom ...)}`. Build one
with [[new-client]] or [[client-from-env]]; every function below takes it
first.
Example:
```clojure
(require '[bsdkrun.client :as client])
(def c (client/client-from-env))
(doseq [m (client/list-machines c)] (println (:id m)))
(def result (client/exec! c "abc123" ["uname" "-a"]))
(println (String. (:output result)))
```(client-from-env)(client-from-env env)Build a client from BSDKRUN_URL / BSDKRUN_TOKEN.
A URL set without a token is an error, not a silent unauthenticated
fallback — mirrors daemon/src/client.rs's RemoteConfig::from_env (which
uses BSDKRUN_HOST/BSDKRUN_TOKEN for the gRPC client; these are
GraphQL-specific env vars with a different URL shape, not aliases).
The 1-arity form takes an explicit {String -> String} env map instead of
reading System/getenv — dependency injection for tests, the same
approach bsdkrun.binary uses, since the JVM offers no supported way to
mutate real process environment variables at runtime.
Throws errors/missing-config if BSDKRUN_URL is unset, or set without
BSDKRUN_TOKEN.
Build a client from `BSDKRUN_URL` / `BSDKRUN_TOKEN`.
A URL set without a token is an error, not a silent unauthenticated
fallback — mirrors `daemon/src/client.rs`'s `RemoteConfig::from_env` (which
uses `BSDKRUN_HOST`/`BSDKRUN_TOKEN` for the gRPC client; these are
GraphQL-specific env vars with a different URL shape, not aliases).
The 1-arity form takes an explicit `{String -> String}` env map instead of
reading `System/getenv` — dependency injection for tests, the same
approach `bsdkrun.binary` uses, since the JVM offers no supported way to
mutate real process environment variables at runtime.
Throws `errors/missing-config` if `BSDKRUN_URL` is unset, or set without
`BSDKRUN_TOKEN`.(commit! client id name)(commit! client id name description)Snapshot a machine into a named flavor, like docker commit.
Snapshot a machine into a named flavor, like `docker commit`.
(exec! client id command)(exec! client id command {:keys [env]})Run a command to completion and collect its output.
Implemented as the three-operation sequence daemon/README.md documents:
openShell (with a command:, so the session runs it instead of a login
shell), THEN subscribe to shellOutput (so nothing written in between is
lost), THEN wait for an exit code. closeShell always runs, whether the
wait succeeded, failed, or timed out.
opts: :env — a map of K -> V, or a ["K=V" ...] vector.
Returns {:exit-code ... :output <byte[]>}. Blocks the calling thread.
Run a command to completion and collect its output.
Implemented as the three-operation sequence `daemon/README.md` documents:
`openShell` (with a `command:`, so the session runs it instead of a login
shell), THEN subscribe to `shellOutput` (so nothing written in between is
lost), THEN wait for an exit code. `closeShell` always runs, whether the
wait succeeded, failed, or timed out.
`opts`: `:env` — a map of `K -> V`, or a `["K=V" ...]` vector.
Returns `{:exit-code ... :output <byte[]>}`. Blocks the calling thread.(follow-logs client id handlers)Stream a machine's console log live over a subscription.
handlers is {:follow :boot :on-data :on-error :on-complete} — :follow
defaults true, :boot defaults false; :on-data receives binary-safe
decoded chunks (a byte[]).
Returns a zero-arg function that stops following.
Stream a machine's console log live over a subscription.
`handlers` is `{:follow :boot :on-data :on-error :on-complete}` — `:follow`
defaults true, `:boot` defaults false; `:on-data` receives binary-safe
decoded chunks (a `byte[]`).
Returns a zero-arg function that stops following.(get-machine client id)A machine by id, name, or unique id prefix. Returns nil if no such machine exists.
A machine by id, name, or unique id prefix. Returns nil if no such machine exists.
(list-machines client)(list-machines client {:keys [all]}){:all true} includes stopped machines too (default running only).
Returns a vector of sandbox-info maps (see
bsdkrun.types/sandbox-info-from-graphql) — the same shape
bsdkrun.sandbox/list returns.
`{:all true}` includes stopped machines too (default running only).
Returns a vector of sandbox-info maps (see
`bsdkrun.types/sandbox-info-from-graphql`) — the same shape
`bsdkrun.sandbox/list` returns.(logs client id)(logs client id {:keys [boot]})One-shot console log fetch. {:boot true} shows bsdkrun's own boot log
instead of the guest console. Use follow-logs to stream instead.
One-shot console log fetch. `{:boot true}` shows bsdkrun's own boot log
instead of the guest console. Use [[follow-logs]] to stream instead.(new-client {:keys [url token]})Build a client from an explicit {:url ... :token ...} map. Does not
connect yet — the HTTP client is cheap to hold, and the websocket is opened
lazily on first subscribe.
Build a client from an explicit `{:url ... :token ...}` map. Does not
connect yet — the HTTP client is cheap to hold, and the websocket is opened
lazily on first [[subscribe]].(normalize-url input)Trim, add http:// if no scheme was given, strip trailing slashes, append
/graphql unless the path already ends with it. Mirrors
web/src/lib/connection.ts's normalizeUrl exactly.
Trim, add `http://` if no scheme was given, strip trailing slashes, append `/graphql` unless the path already ends with it. Mirrors `web/src/lib/connection.ts`'s `normalizeUrl` exactly.
(remove! client ids)(remove! client ids {:keys [force]})Remove one or more machines. ids is a single id or a collection of
them. {:force true} stops them first if running.
Remove one or more machines. `ids` is a single id or a collection of
them. `{:force true}` stops them first if running.(request client query)(request client query variables)Run an arbitrary query or mutation. Every typed method in this namespace is implemented in terms of this — it exists as a public escape hatch for documents this SDK has no typed wrapper for yet.
Returns body["data"] (String-keyed, as parsed by clojure.data.json).
Throws errors/auth-error on HTTP 401, or a GraphQL error with
extensions.code == "UNAUTHENTICATED". Throws errors/graphql-error on
transport failure, a non-JSON response, or any other GraphQL error.
Run an arbitrary query or mutation. Every typed method in this namespace is implemented in terms of this — it exists as a public escape hatch for documents this SDK has no typed wrapper for yet. Returns `body["data"]` (String-keyed, as parsed by `clojure.data.json`). Throws `errors/auth-error` on HTTP 401, or a GraphQL error with `extensions.code == "UNAUTHENTICATED"`. Throws `errors/graphql-error` on transport failure, a non-JSON response, or any other GraphQL error.
(run-bsd! client opts)Boot a FreeBSD/NetBSD guest. :os is :freebsd/:netbsd (a keyword, or
the equivalent string). Returns the new machine's id.
Boot a FreeBSD/NetBSD guest. `:os` is `:freebsd`/`:netbsd` (a keyword, or the equivalent string). Returns the new machine's id.
(run-flavor! client opts)Boot a saved flavor by name. Returns the new machine's id.
Boot a saved flavor by name. Returns the new machine's id.
(run-linux! client opts)Boot a Linux OCI image. Returns the new machine's id.
Boot a Linux OCI image. Returns the new machine's id.
(run-nanos! client opts)Boot a Nanos unikernel. No agent (no exec!/shell!), but it does have a
root disk, so :persist is the one disk option it takes. Returns the new
machine's id.
Boot a Nanos unikernel. No agent (no exec!/shell!), but it does have a root disk, so `:persist` is the one disk option it takes. Returns the new machine's id.
(run-osv! client opts)Boot an OSv unikernel. Like Nanos, no agent, but it does have a root
filesystem, so the disk options apply — :disk in particular, how an
x86_64 guest gets a filesystem (its loader ELF is kernel only). Returns the
new machine's id.
Boot an OSv unikernel. Like Nanos, no agent, but it does have a root filesystem, so the disk options apply — `:disk` in particular, how an x86_64 guest gets a filesystem (its loader ELF is kernel only). Returns the new machine's id.
(run-unikraft! client opts)Boot a Unikraft unikernel. No disk and no agent, so no
volume/persist/repo/command options — :mounts (virtio-fs shares) is the
exception, needing neither. Returns the new machine's id.
Boot a Unikraft unikernel. No disk and no agent, so no volume/persist/repo/command options — `:mounts` (virtio-fs shares) is the exception, needing neither. Returns the new machine's id.
(shell! client id)(shell! client id {:keys [command env rows cols] :or {rows 24 cols 80}})Open a live interactive session. Unlike exec!, this returns
immediately with a handle whose :on-output!/:on-exit! callbacks fire as
output arrives.
The shellOutput subscription starts as soon as this function sets it up
— necessarily before the caller can register a callback on the returned
handle — so any output/exit that arrives in that window is buffered and
replayed to a callback the moment one is registered, never dropped. (This
exact race was found and fixed in two other SDKs' shell() during
review.)
opts: :command (nil opens a login shell), :env, :rows (default 24),
:cols (default 80).
Returns a handle map: {:id :write! :resize! :close! :on-output! :on-exit!}.
Open a live interactive session. Unlike [[exec!]], this returns
immediately with a handle whose `:on-output!`/`:on-exit!` callbacks fire as
output arrives.
The `shellOutput` subscription starts as soon as this function sets it up
— necessarily before the caller can register a callback on the returned
handle — so any output/exit that arrives in that window is buffered and
replayed to a callback the moment one is registered, never dropped. (This
exact race was found and fixed in two other SDKs' `shell()` during
review.)
`opts`: `:command` (nil opens a login shell), `:env`, `:rows` (default 24),
`:cols` (default 80).
Returns a handle map: `{:id :write! :resize! :close! :on-output!
:on-exit!}`.(start! client id)Restart a stopped machine in place. Returns a command-result map.
Restart a stopped machine in place. Returns a command-result map.
(stop! client id)Stop the machine. Returns a command-result map.
Stop the machine. Returns a command-result map.
(subscribe client query variables handlers)Start a subscription over the shared websocket (opened lazily on first
use). handlers is {:on-next :on-error :on-complete}, all optional.
A subscribe message is queued until connection_ack arrives if the
socket has not acked yet, exactly like web/src/lib/graphql.ts's
subscribe.
Returns a zero-arg function that unsubscribes (sends complete, then
closes the socket if this was the last live subscription).
Start a subscription over the shared websocket (opened lazily on first
use). `handlers` is `{:on-next :on-error :on-complete}`, all optional.
A `subscribe` message is queued until `connection_ack` arrives if the
socket has not acked yet, exactly like `web/src/lib/graphql.ts`'s
`subscribe`.
Returns a zero-arg function that unsubscribes (sends `complete`, then
closes the socket if this was the last live subscription).(update! client id)(update! client id {:keys [cpus mem]})Change the recorded vCPU / RAM. Applies on the next start!.
Change the recorded vCPU / RAM. Applies on the next [[start!]].
(ws-url http-url)Derive the websocket endpoint from the HTTP one: http:// -> ws://,
https:// -> wss://, trailing slashes on the path stripped, /ws
appended. Mirrors web/src/lib/graphql.ts's wsUrl.
Derive the websocket endpoint from the HTTP one: `http://` -> `ws://`, `https://` -> `wss://`, trailing slashes on the path stripped, `/ws` appended. Mirrors `web/src/lib/graphql.ts`'s `wsUrl`.
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 |