OpenAPI search-and-execute for LLM agents, Cloudflare-codemode style.
Drop in an OpenAPI spec; get two tools: search_apis (LLM-written JS
filters the spec's slim operation index as data in a sandbox) and
execute_api_code (LLM-written JS calls apis.<name>.request(),
intercepted, validated against the spec, credentialed, and executed in
Elixir). Credentials never enter the sandbox.
See docs/plans/2026-08-16-openapi-search-execute-design.md for the design.
Summary
Functions
Take a raw spec apart into %OapiCodemode.Decomposed{}, ready to put
into an OapiCodemode.SpecStore. See OapiCodemode.Ingest.decompose/1.
Ingest a raw spec into the registry's own store and register it in one call.
Register the spec at {store, ref} under name.
Emit the search/execute tool definitions. See OapiCodemode.Tools.definitions/1.
Functions
Take a raw spec apart into %OapiCodemode.Decomposed{}, ready to put
into an OapiCodemode.SpecStore. See OapiCodemode.Ingest.decompose/1.
@spec ingest_and_register(GenServer.server(), String.t(), String.t(), keyword()) :: :ok | {:error, term()}
Ingest a raw spec into the registry's own store and register it in one call.
The small-spec path: the spec lands in a private
OapiCodemode.SpecStore.ETS table owned by the registry process, so it
lives exactly as long as the registry does.
Returns {:error, {:invalid_config_option, key}} rather than raising when
config_opts contains a key ApiConfig doesn't define (e.g. a typo'd
option name) — a host building config from user/config-file input gets a
value it can act on instead of a KeyError crash.
A refusal leaves nothing behind: this is the one path that writes into the
private store, so when the put lands and register/4 then refuses (a
name that is not a JS identifier, an index too large, a bad idempotency
header), the projection nothing came to bind is collected before the error
is returned. See OapiCodemode.Registry.collect_unreferenced/2.
@spec register( GenServer.server(), String.t(), {OapiCodemode.SpecStore.store(), OapiCodemode.SpecStore.ref()}, keyword() ) :: :ok | {:error, term()}
Register the spec at {store, ref} under name.
A registration is a binding, not a copy: the library holds the store and
the projection ref, reads meta/2 and index/2 once, and reads
everything else per call. Hosts that keep specs in a database of their own
implement OapiCodemode.SpecStore and register the ref; hosts with one
small spec use ingest_and_register/4, which puts it into the registry's
own ETS store.
See OapiCodemode.Registry.register/4 for the refusals.
Emit the search/execute tool definitions. See OapiCodemode.Tools.definitions/1.