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.
This page describes the target state of the in-progress modularisation programme tracked in #1126. Rows marked carved below already live in their target module; every other row still ships inside llm4s-core, and its target-module column says where it is heading, not where it lives today.
What has actually moved so far, in the build but not yet in a release:
| Slice | Modules carved | Status |
|---|---|---|
| 1 | llm4s-rag, llm4s-knowledgegraph |
in the build, unpublished |
| 2 | llm4s-memory, llm4s-memory-postgres |
in the build, unpublished |
| 3 | llm4s-mcp, llm4s-media, llm4s-image, llm4s-speech |
in the build, unpublished |
| 4 | none - the provider registration SPI (ProviderDescriptor, discovered through META-INF/services) that slice 5’s modules register through |
in the build, unpublished |
| 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 |
in the build, unpublished |
| 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 |
in the build, unpublished |
| 7 | llm4s-agent-tools (the built-in tools and their config), llm4s-agent (agent, assistant) |
in the build, unpublished |
The latest release tag is v0.4.1, which is still a single llm4s-core (0.4.0 was the artifact rename only, #1141). The first release to publish separate module artifacts will be 0.5.0, in slice 8 (#1281); it is also the MiMa baseline. Until it is published 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/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 — 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 |
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 |
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 |
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, toolapi/WorkspaceTools — containerised workspace execution: the client (ContainerisedWorkspace, WorkspaceTools, 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 |
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/providerinllm4s-corenow holds only the plumbing every provider module shares - cost estimation, HTTP error mapping, metrics recording, theEmbeddingProvidertrait, exchange recording - and no client. With the registration SPI inllmconnect/spifrom 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 aProviderDescriptorlisted in its own module’sLlm4sProviderModule, so adding one adds a dependency and edits nothing in core. See Writing a provider. Helpers specific to one wire format live with it -ResponseFormatMapperandToolCallDeserializerinllm4s-openai-compatible, OpenAI’s model-name rules inllm4s-openai- and helpers only llm4s’s own modules use, such asProviderResultOps, areprivate[llm4s]. Vendor API keys (llm4s.credentials.<provider>.apiKey) are read by core’sconfig, but each key is bound in its provider module’sreference.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 aTracingBackendregistered inMETA-INF/services, discovered byTRACING_MODE, the way a provider is aProviderDescriptor. 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.mediais a new package, not a carve. It consolidates the three overlapping image-format enumerationsllm4s-corehad accumulated, so thatllm4s-imageandllm4s-speechcarve 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.extractis 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.graphragkeeps its package name but ships inllm4s-rag, notllm4s-knowledgegraph.GraphRAGandvectorstorereferenced each other, which made the two modules inseparable; moving the one file that reaches intovectorstorebroke the cycle. Package names track the API; module boundaries track the dependency graph, and here they disagree.llm4s-memorysplits in two.PostgresMemoryStorewas the only file inagent/memorythat needed a connection pool and a server-side driver, so it ships asllm4s-memory-postgres; keeping it with the rest would mean anyone using agent memory at all inherits HikariCP and the Postgres JDBC driver.llm4s-memoryitself carries only sqlite-jdbc, for the two file-backed stores.org.llm4s.vectorstore.PostgresVectorHelpersships inllm4s-core, not inllm4s-ragwith the rest oforg.llm4s.vectorstore. It is a pureArray[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-ragandllm4s-memory-postgres); the module they share is core. This is the same package-versus-module disagreement asgraphrag, 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
0.5.0publishes the split modules,mimaPreviousArtifactsenforces 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 supported minimum is JDK 21 for every artifact, and CI runs only JDK 21. For llm4s-core and everything that depends on it, which is every artifact but two, JDK 21 is also a hard requirement, for the reasons in the table. Whether some artifacts will get a lower floor before 1.0 is an open decision (#1493); until it is made, this table is what the code needs today.
| Artifacts | Minimum JDK | Tested on | Why |
|---|---|---|---|
llm4s-agent, and the modules that depend on it: llm4s-java-api, 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 (supported) | 21 | neither depends on llm4s-core: they use no JDK 21 API, and their newest dependency class files are version 55 (uJson), so they may well load on an older JDK, but only JDK 21 is tested and supported |
No build setting pins a bytecode level (no -release, -java-output-version or javacOptions target), so the bytecode level alone does not tell you which JDK you need: the requirement comes from the APIs and the dependencies above. The Scala compiler emits class-file version 52 for the llm4s Scala sources. The few Java sources (the @Stable and @Experimental annotations in llm4s-core, the enums and value types of llm4s-java-api) are compiled by javac at the level of the JDK that builds them, which is version 65 for artifacts built on CI’s JDK 21. The Gradle-built llm4s-kotlin-api targets JVM 17 bytecode (version 61) and still needs JDK 21 to run.
Programme status
For current progress against this target structure, see the tracking issue #1126 and its slice sub-issues.