1.0 Scope

This page states which parts of the LLM4S API are safe to build on ahead of a 1.0 freeze.

Until 0.4.1 all of it shipped in one core Maven artifact of roughly 84k lines — agent runtime, RAG, MCP, speech, image, knowledge graph, and eleven provider clients together. There was no way to tell from the artifact alone which parts of that surface are meant to be a long-term contract and which are still moving fast.

The modularisation programme tracked in #1126 split it up. Rows marked carved below live in their target module; any other row still ships inside llm4s-core, and its target-module column says where it is heading, not where it lives today.

The carves, all published from 0.5.0:

Slice Modules carved Status
1 llm4s-rag, llm4s-knowledgegraph published in 0.5.0
2 llm4s-memory, llm4s-memory-postgres published in 0.5.0
3 llm4s-mcp, llm4s-media, llm4s-image, llm4s-speech published in 0.5.0
4 none - the provider registration SPI (ProviderDescriptor, discovered through META-INF/services) that slice 5’s modules register through published in 0.5.0
5 llm4s-ollama, llm4s-gemini, llm4s-anthropic, llm4s-openai, llm4s-openai-compatible (with Mistral and Cohere), llm4s-voyage - llm4s-core now holds no provider client published in 0.5.0
6 llm4s-observability (Langfuse, the trace collector, CostTracker); OpenTelemetryConfig joins the existing llm4s-observability-otel; llm4s-observability-prometheus (Prometheus). The tracing and metrics contracts stay in llm4s-core, which declares no observability dependency published in 0.5.0
7 llm4s-agent-tools (the built-in tools and their config), llm4s-agent (agent, assistant) published in 0.5.0

0.5.0 is the first release to publish separate module artifacts (0.4.x was a single llm4s-core; 0.4.0 was the artifact rename only, #1141). It sets no MiMa baseline: that comes at a pre-1.0 release, version to be decided, once the designs are final (#1281). Until then nothing is frozen: “Frozen at 1.0” is the tier a module will hold, not a constraint on changing it now.

Maturity Legend

These definitions are shared with the Roadmap so the two pages agree.

Status Meaning
Frozen at 1.0 Source and binary compatible within the 1.x series once published under its target module. This is the compatibility promise 1.0 makes.
Beta Implemented and usable, but API, provider behavior, or docs still need hardening before v1.0.
Experimental Useful prototype or advanced feature; expect changes.
Planned Roadmap item, design, issue, or PR queue item; not a stable user contract.

Package Map

Every top-level package under modules/core/src/main/scala/org/llm4s/, its target module, and its tier.

Package Target module Tier
types llm4s-core Frozen at 1.0
error llm4s-core Frozen at 1.0
config llm4s-core Frozen at 1.0
model llm4s-core Frozen at 1.0
toolapi — the tool API: ToolFunction, ToolRegistry, schemas, execution llm4s-core Frozen at 1.0
toolapi/builtin, toolapi/tools — the built-in tools (core utilities, filesystem, HTTP, shell, Brave/DuckDuckGo/Exa search) and ToolsConfigLoader — carved llm4s-agent-tools Beta
context llm4s-core Frozen at 1.0
util llm4s-core Frozen at 1.0
syntax llm4s-core Frozen at 1.0
identity llm4s-core Frozen at 1.0
resource llm4s-core Frozen at 1.0
core llm4s-core Frozen at 1.0
http llm4s-core Frozen at 1.0
security llm4s-core Frozen at 1.0
llmconnect (API only — see provider split below) llm4s-core Frozen at 1.0
reliability llm4s-core Frozen at 1.0
agent (excludes agent/memory) — carved llm4s-agent Frozen at 1.0
assistant — carved llm4s-agent Beta
trace — the contract: Tracing, TraceEvent, TracingComposer, TracingMode, the trace/spi TracingBackend SPI, NoOpTracing, ConsoleTracing, and TracingSettings (in llmconnect/config) llm4s-core Frozen at 1.0
metrics — the contract: MetricsCollector llm4s-core Frozen at 1.0
trace — Langfuse (LangfuseTracing, its batch sender and TracingBackend), TraceCollectorTracing, trace/model, trace/store; metrics — CostTracker — carved llm4s-observability Beta
trace — OpenTelemetry (OpenTelemetryTracing, OpenTelemetryConfig) — carved llm4s-observability-otel (modules/trace-opentelemetry) Beta
metrics — Prometheus (PrometheusMetrics, PrometheusEndpoint, MetricsConfigLoader) — carved llm4s-observability-prometheus Beta
metrics — Micrometer (MicrometerMetrics), a MetricsCollector over a MeterRegistry — new llm4s-observability-micrometer Beta
llmconnect/provider — OpenAI, Azure and Requesty (the providers sharing OpenAIClient) — carved llm4s-openai Frozen at 1.0
llmconnect/auth/azure — AzureEntraId: Microsoft Entra ID tokens (DefaultAzureCredential, any TokenCredential) for the azure provider’s authentication = "entra-id" (#2274) — new llm4s-azure-identity (modules/providers/azure-identity); carries Azure’s azure-identity Experimental
llmconnect/provider — OpenRouter, DeepSeek, Z.ai and the generic openai-compatible provider, on one SDK-free OpenAICompatibleClient — carved llm4s-openai-compatible Frozen at 1.0
llmconnect/provider — Anthropic — carved llm4s-anthropic Frozen at 1.0
llmconnect/provider — Gemini (and Vertex AI) — carved llm4s-gemini Frozen at 1.0
llmconnect/provider — Ollama — carved llm4s-ollama Frozen at 1.0
llmconnect/provider — Mistral and Cohere, as dialects on OpenAICompatibleClient — carved llm4s-openai-compatible Beta
llmconnect/provider — xAI (Grok), as a dialect on OpenAICompatibleClient (#1023) — new llm4s-openai-compatible Beta
llmconnect/provider — Voyage AI embeddings — carved llm4s-voyage (modules/providers/voyage) Beta
llmconnect/provider — AWS Bedrock (Converse, ConverseStream) — new llm4s-bedrock (modules/providers/bedrock) Beta
llmconnect/provider — Jina AI embeddings — new llm4s-jina (modules/providers/jina) Beta
llmconnect/provider — Cohere embeddings, on Cohere’s native /v2/embed (Cohere chat is a dialect in llm4s-openai-compatible) — new llm4s-cohere (modules/providers/cohere) Beta
llmconnect/provider — IBM watsonx.ai, on the chat endpoints (never run against the live service: verification against it is still open in #1314) — new llm4s-watsonx (modules/providers/watsonx) Beta
llmconnect/provider — other community providers llm4s-openai-compatible dialects, or modules/providers/<name> Beta
jev — typed client for TypeSafe’s Jev decision model (Noul, Choice, Score); not a chat provider — new llm4s-jev (modules/providers/jev) Beta
testkit — the checks a provider module’s Llm4s<Name>ModuleSpec makes (ProviderModuleChecks, ProviderTestConfig, CredentialsRoundTrip, LocalProviderTestServer), formerly unpublished helpers in core’s test sources — new llm4s-provider-testkit (modules/provider-testkit), a test-scope dependency; requires JDK 21 (virtual threads) Beta
agent/graph/sqlite — SqliteCheckpointer, the first durable Checkpointer: threads, events and run claims in one SQLite file that survives a restart and that several processes on one host can share — new llm4s-agent-checkpoint-sqlite (modules/agent-checkpoint-sqlite); carries the SQLite JDBC driver Beta
agent/graph/postgres — PostgresCheckpointer: threads, events and run claims in a PostgreSQL schema that runtimes on several machines share, claims and retention by the database’s clock — new llm4s-agent-checkpoint-postgres (modules/agent-checkpoint-postgres); carries the PostgreSQL JDBC driver and HikariCP Beta
schema — SchemaOf, a JSON schema derived from a case class with derives, and completeStructuredOf; builds core’s ObjectSchema and adds no dependency (Map, recursive types and sealed hierarchies with fields are refused at compile time; a recursion through a hand-written given that derives its type fails on first use) — new llm4s-schema-derivation (modules/schema-derivation) Experimental
testkit — a scriptable fake LLMClient for the tests of code that uses llm4s (ScriptedLLMClient, Reply, RecordedCall, UnscriptedCallError) — new llm4s-testkit (modules/testkit), a test-scope dependency Beta
doctor — the setup checker: DoctorCli (its options, text report, JSON output and exit codes are a user contract), Doctor.run and its report, run on the application’s own classpath — new llm4s-doctor (modules/doctor), usually a test-scope dependency Experimental
agent/harness/memory — SemanticMemoryMiddleware: recall before a turn, recording and consolidation after it, one store per tenant, each write a replayable effect on a TransactionalMemoryStore — new llm4s-agent-memory (modules/agent-memory); depends on llm4s-agent and llm4s-memory Experimental
agent/testkit — CheckpointerContract, the contract every Checkpointer must pass (commits, event numbering, compaction, run-claim leases and fencing, two runtimes over one store), and ManualClock — new llm4s-agent-testkit (modules/agent-testkit), a test-scope dependency; requires JDK 21 (virtual threads) Beta
build — the bill of materials that pins every published artifact to one version (no code) — new llm4s-bom (modules/bom) Beta
rag, vectorstore, chunking, reranker, eval — carved llm4s-rag Beta
extract (consolidated from rag/extract + llmconnect/extractors) and rag/embed (from llmconnect/encoding) — carved llm4s-rag Beta
vectorstore.elasticsearch — ElasticsearchVectorStore, a VectorStore over the Elasticsearch REST API (dense_vector kNN, metadata filters, _bulk), with ElasticsearchConfig and ElasticsearchVectorStoreConfigLoader; no Elasticsearch client library — new llm4s-vectorstore-elasticsearch (modules/vectorstore-elasticsearch) Experimental
vectorstore.opensearch — OpenSearchVectorStore, the OpenSearch dialect of the same store (knn_vector with the k-NN plugin, the knn query, efficient or post-filtering per engine), with OpenSearchConfig and OpenSearchVectorStoreConfigLoader — new llm4s-vectorstore-elasticsearch (modules/vectorstore-elasticsearch) Experimental
vectorstore.redis — RedisVectorStore, a VectorStore over Redis Query Engine (Redis Stack, Redis 8+) or Valkey’s valkey-search (FT.CREATE vector index over hashes, KNN FT.SEARCH, metadata filters as TAG clauses), with RedisConfig and RedisVectorStoreConfigLoader; Jedis, kept out of the API — new llm4s-vectorstore-redis (modules/vectorstore-redis) Experimental
agent/memory (excluding PostgresMemoryStore) — carved llm4s-memory Beta
agent/memory/PostgresMemoryStore — carved llm4s-memory-postgres Beta
mcp - carved llm4s-mcp Beta
knowledgegraph/neo4j — the Neo4j graph store (Neo4jGraphStore) llm4s-knowledgegraph-neo4j (modules/knowledgegraph-neo4j) Experimental
workspace, shared, codegen, agent/harness/workspace — containerised workspace execution: the client (ContainerisedWorkspace, the harness backends WorkspaceFileBackend and WorkspaceSandboxBackend, the code-generation worker) and the wire protocol it speaks to the runner image (WorkspaceAgentProtocol, WorkspaceAgentInterface) llm4s-workspace-client, llm4s-workspace-shared (modules/workspace) Experimental
media - new llm4s-media Beta
speech - carved llm4s-speech Experimental
imagegeneration, imageprocessing - carved llm4s-image Experimental
knowledgegraph — carved (knowledgegraph/graphrag ships in llm4s-rag) llm4s-knowledgegraph Experimental
javaapi — the Java facade (Llm4s, JLlmClient, JAgent, AgentStream, AgentStreamListener, StreamEvents, Answer, PendingInterrupt, InterruptKind, BreakpointPhase, ConversationBuilder, LlmResult, LlmException) — new llm4s-java-api (modules/java-api) Beta
javaapi.rag — the Java facade for RAG (JRag, JRagBuilder, JRagStore, JRagAnswer, JRagSource) over llm4s-rag, in a module of its own so a chat-only Java user does not receive llm4s-rag’s dependencies — new llm4s-java-rag (modules/java-rag) Experimental
javaapi.reactor — Reactor for the Java facade (Streams.toFlux: a streamed reply as a Flux<String>), in a module of its own so llm4s-java-api does not bring reactor-core — new llm4s-reactor (modules/reactor) Experimental
spring — Spring Boot auto-configuration (Llm4sAutoConfiguration, Llm4sProperties, LLM4STemplate, LlmHealthIndicator) — new llm4s-spring-boot-starter (modules/spring-boot-starter) Beta
effect.cats — LLMClientIO, AgentIO (cats-effect 3, fs2) — new llm4s-effect (modules/llm4s-effect) Beta
zio — LLMClientZ, AgentZ (ZIO 2, ZIO Streams) — new llm4s-zio (modules/llm4s-zio) Beta
kotlin — coroutine API (LLMClientKt, AgentKt, AgentStreamItem); a separate Gradle build, not part of sbt or the MiMa baseline, published with each release at the release’s version (no _3 suffix; managed by llm4s-bom) — new llm4s-kotlin-api (modules/kotlin-api) Experimental
pekko — LLMClientPekko, AgentPekko (Apache Pekko Streams) — new llm4s-pekko (modules/llm4s-pekko) Beta

Notes:

  • llmconnect/provider in llm4s-core now holds only the plumbing every provider module shares - cost estimation, HTTP error mapping, metrics recording, the EmbeddingProvider trait, exchange recording - and no client. With the registration SPI in llmconnect/spi from slice 4 and the streaming and request helpers providers build on, it is a frozen provider-author SPI, public so that a provider can be published outside this repository: a provider is a ProviderDescriptor listed in its own module’s Llm4sProviderModule, so adding one adds a dependency and edits nothing in core. See Writing a provider. Helpers specific to one wire format live with it - ResponseFormatMapper and ToolCallDeserializer in llm4s-openai-compatible, OpenAI’s model-name rules in llm4s-openai - and helpers only llm4s’s own modules use, such as ProviderResultOps, are private[llm4s]. Vendor API keys (llm4s.credentials.<provider>.apiKey) are read by core’s config, but each key is bound in its provider module’s reference.conf, beside the descriptor that uses it.
  • The tracing and metrics contracts stay in llm4s-core, and they are what is frozen: llmconnect, the agent runtime and every provider module trace and record metrics through them alone. The integrations are separate modules that plug into that contract - a tracing backend is a TracingBackend registered in META-INF/services, discovered by TRACING_MODE, the way a provider is a ProviderDescriptor. They are Beta, like every integration module other than the frozen provider modules: Langfuse’s ingestion format and OpenTelemetry’s SDK move on their vendors’ schedule, not ours, and a new tracing backend should be a new module rather than a change to the frozen surface. See the migration guide.
  • Rows marked carved already live in their target sbt module. Their package names are unchanged, so this is a build-file change for users, not an import rewrite — with one exception, org.llm4s.extract, described in the migration guide.
  • org.llm4s.media is a new package, not a carve. It consolidates the three overlapping image-format enumerations llm4s-core had accumulated, so that llm4s-image and llm4s-speech carve as pure file moves rather than moves plus a vocabulary change. It is the one part of slice 3 with a source break, described in the migration guide; it is deliberate and taken now rather than after 1.0.
  • org.llm4s.extract is a new package name, not a rename of an existing one — see Slice 1 for why the two extractors were consolidated rather than just moved.
  • org.llm4s.knowledgegraph.graphrag keeps its package name but ships in llm4s-rag, not llm4s-knowledgegraph. GraphRAG and vectorstore referenced each other, which made the two modules inseparable; moving the one file that reaches into vectorstore broke the cycle. Package names track the API; module boundaries track the dependency graph, and here they disagree.
  • llm4s-memory splits in two. PostgresMemoryStore was the only file in agent/memory that needed a connection pool and a server-side driver, so it ships as llm4s-memory-postgres; keeping it with the rest would mean anyone using agent memory at all inherits HikariCP and the Postgres JDBC driver. llm4s-memory itself carries only sqlite-jdbc, for the two file-backed stores.
  • org.llm4s.vectorstore.PostgresVectorHelpers ships in llm4s-core, not in llm4s-rag with the rest of org.llm4s.vectorstore. It is a pure Array[Float] ⇄ pgvector-text codec with no JDBC types in it, and it has consumers in two modules that must not depend on each other (llm4s-rag and llm4s-memory-postgres); the module they share is core. This is the same package-versus-module disagreement as graphrag, in the other direction.
  • Vertex AI ships in llm4s-gemini. It only calls Google’s Gemini models, in the same JSON format as the Gemini API, and differs in endpoint and OAuth authentication rather than in dependencies - so bundling costs Gemini-API users nothing, whereas splitting it out after release would be a breaking move. See the migration guide.

What Frozen means

  • Source and binary compatible within 1.x. Once the pre-1.0 baseline is set, mimaPreviousArtifacts enforces binary compatibility on every Frozen module for all subsequent 1.x releases.
  • Deprecate before removing. A Frozen API is only removed after a deprecation cycle, never dropped outright in a minor release. See the Compatibility and Deprecation Policy.
  • Beta and Experimental can move faster. They may change in a minor release, but a migration note ships with the change in the same release’s CHANGELOG.

Scala and JDK support

1.0 targets Scala 3 only (3.7.1). Scala 2.13 support is deferred to post-1.0 and, if it happens, would target the frozen spine (llm4s-core, llm4s-agent, and the frozen provider modules) rather than the full tree. The tracing and metrics contracts are part of llm4s-core; the observability integration modules are not in the spine. JDK 21 is used in CI; the JDK each artifact needs is below.

See #1126 for the reasoning behind the Scala-3-only decision.

JDK. The minimum is JDK 21 for every artifact, and CI runs only JDK 21. This is the one support statement: the README and the other pages link here, and scripts/check-doc-support.sh fails CI when a page states another floor. For llm4s-core and everything that depends on it, which is every artifact but two, JDK 21 is a hard requirement for the reasons in the table, and every artifact is compiled to JDK 21 bytecode, so an older JDK refuses it at once with UnsupportedClassVersionError.

Artifacts Minimum JDK Tested on Why
llm4s-agent, and the modules that depend on it: llm4s-java-api, llm4s-java-rag, llm4s-reactor, llm4s-kotlin-api, llm4s-spring-boot-starter, llm4s-effect, llm4s-zio, llm4s-agent-testkit 21 21 llm4s-agent depends on Ox, whose jars are compiled for JDK 21 (class-file version 65), and it starts virtual threads (Thread.ofVirtual). The Java and Kotlin facades start their own as well: AgentStream in llm4s-java-api, and AgentKt’s stream completion in llm4s-kotlin-api (#1678), and llm4s-agent-testkit’s CheckpointerContract runs its cases on virtual threads
llm4s-core and every module that depends on it 21 21 ToolRegistry starts a virtual thread (Thread.ofVirtual), a JDK 21 API, so llm4s-core does not compile against an older JDK
llm4s-provider-testkit 21 21 its interruption checks and LocalProviderTestServer run on virtual threads (#1582)
llm4s-media, llm4s-workspace-shared 21 21 neither depends on llm4s-core or uses a JDK 21 API, but they are compiled to JDK 21 bytecode like every other artifact, and only JDK 21 is tested

Bytecode. The build pins the bytecode level to the minimum (Common.javaRelease in project/Dependencies.scala): the Scala compiler gets -java-output-version 21 and javac gets --release 21, so every class is class-file version 65 whichever JDK runs the build, and the build cannot use an API newer than JDK 21. The Gradle builds match it: llm4s-kotlin-api targets JvmTarget.JVM_21 with release 21 for Java, and the Gradle Java sample compiles with release 21. scripts/check-doc-support.sh fails CI when a project or a Gradle build targets another level, and JavaReleaseSpec in llm4s-core, llm4s-agent and llm4s-java-api reads the compiled classes’ version. Up to 0.5.1 nothing pinned it: the Scala classes were version 52 and only the few Java sources (@Stable, @Experimental, and llm4s-java-api’s enums and value types) were 65, built on JDK 21, so the bytecode did not show the floor.

Why not JDK 17 for some artifacts (#1493). A lower floor for a chat-only subset, with Ox made optional or JAgent split from llm4s-java-api, was considered and rejected: llm4s-core itself starts a virtual thread (ToolRegistry), the provider modules and llm4s-java-api depend on core, and the cancellation contract (interrupts that close a blocking socket read) is defined on JDK 21 virtual threads. A JDK 17 floor would mean a second code path for core and every provider, and a second JDK in CI, for a pre-1.0 library whose agent runtime needs 21 regardless.

Programme status

For current progress against this target structure, see the tracking issue #1126 and its slice sub-issues.