Skip to content

What's New in 4.0

Atmosphere 4.0 is the JDK 21+ rewrite of the framework. The 4.0.0 release shipped the core platform migration (Jakarta EE 10, virtual threads, Jetty 12 / Tomcat 11, rooms, AI streaming SPI, MCP, TypeScript client). Since then the 4.0.x line has grown into a full multi-agent runtime — unified agent annotations, twelve pluggable AI runtimes, orchestration primitives, WebTransport/HTTP3, React Native support, and major compatibility refreshes.

GraalVM Native Image is deliberately not in that list. 4.0.0 produced a native binary that booted, but annotation discovery ran as a classpath scan at startup and a native image has no .class files to scan — so the binary answered a health URL while every annotated endpoint was dead. The 4.0.65-SNAPSHOT section below covers the fix and states exactly which path CI drives and which paths it leaves unproven.

The latest build tracks Spring Boot 4.0.7, Quarkus 3.36.3, Jackson 3.2.1, and atmosphere.js 5.0.41, and requires JDK 21 as a minimum.

This page is a highlights reel. For the per-patch history, see the CHANGELOG.

4.0.65-SNAPSHOT — @ManagedService under GraalVM Native Image

Section titled “4.0.65-SNAPSHOT — @ManagedService under GraalVM Native Image”

What CI asserts. .github/workflows/native-image-ci.yml builds two real native binaries — samples/spring-boot-chat on the Spring Boot 4 starter and samples/quarkus-chat on the Quarkus extension — starts each one, opens a long-polling connection to /atmosphere/chat, and fails unless the application log contains connected (broadcaster:, the line only the annotated @Ready method emits. That one line can appear only if the class was discovered, the handler registered, the broadcaster and its by-name-loaded cache created, injection resolved, and the lifecycle fired. Registration itself is silent, so the lane asserts behaviour rather than a startup message.

What CI does not assert — and what is therefore not claimed here: WebSocket under Native Image, SSE, transport negotiation and fallback, @Message encoder/decoder round-trips, rooms / @RoomService / presence / broadcast fan-out, and injection beyond what @Ready requires. Nor the AI stack: no job in the repository builds samples/spring-boot-ai-chat with -Pnative or -Dnative, so @AiEndpoint and @Agent under Native Image remain unproven. A green run on this lane is not “Atmosphere supports GraalVM Native Image” — it is the long-polling @ManagedService path on two runtimes, and nothing more.

Each of these failed quietly. The binary started, a liveness URL answered, and the annotated endpoints were gone:

  • Discovery found nothing. The Spring Boot starter resolved @ManagedService / @AiEndpoint / @Agent with a runtime classpath scan, and a native image has no .class files to scan.
  • Broadcaster caches were unregistered for reflection. org.atmosphere.cache.UUIDBroadcasterCache and three siblings are loaded by name, so creating any Broadcaster failed — and the failure was logged and swallowed, which silently unregistered every @ManagedService on both runtimes.
  • @Message(encoders = …, decoders = …) classes were unregistered. A class named only inside an annotation does not survive the image on its own.

NativeImageMetadataProvider — declare what you load by name

Section titled “NativeImageMetadataProvider — declare what you load by name”

org.atmosphere.nativeimage.NativeImageMetadataProvider is a new public ServiceLoader SPI in atmosphere-runtime: name(), reflectiveTypes(), resourcePatterns(), isAvailable(), priority(). Implement it, list it in META-INF/services/org.atmosphere.nativeimage.NativeImageMetadataProvider, and every integration picks it up. NativeImageMetadata.collect() merges every provider on the classpath and feeds all three consumers — AtmosphereRuntimeHints in the Spring Boot 4 starter, its counterpart in the Spring Boot 3 starter, and the Quarkus deployment processor — each of which previously carried its own transcription of one hardcoded list.

Today atmosphere-runtime is the only module that ships a provider service file (CoreNativeImageMetadataProvider and PoolNativeImageMetadataProvider). The SPI exists so that your modules — and further Atmosphere modules later — can contribute without any integration being edited.

The runtime jar carries its own GraalVM metadata

Section titled “The runtime jar carries its own GraalVM metadata”

atmosphere-runtime.jar now ships META-INF/native-image/org.atmosphere/atmosphere-runtime/reachability-metadata.json, generated from that SPI: 77 reflection entries and 3 resource globs. GraalVM reads the file automatically, so a plain-servlet or embedded-Jetty native build needs no integration module and no configuration to get the runtime’s reflective surface. (No CI lane builds a plain-servlet native binary — that is a property of the jar, not a tested deployment.)

A build-time annotation index, in any build tool

Section titled “A build-time annotation index, in any build tool”

org.atmosphere.nativeimage.AtmosphereAnnotationIndexProcessor is a javac annotation processor auto-discovered from atmosphere-runtime on the compile classpath: depending on the jar is the whole setup. It writes META-INF/atmosphere/annotated-classes.txt per artifact, so build-time discovery is not tied to Spring AOT or Quarkus augmentation. Spring AOT writes the same file through AtmosphereAnnotationScanAotProcessor (registered in the starter’s META-INF/spring/aot.factories); Quarkus builds its map from Jandex instead. atmosphere-runtime itself compiles with <proc>none</proc> — the processor is defined there, so javac cannot run it against that module — and ships a committed index of its own annotation processors, regenerated from AtmosphereReflectiveTypes.annotationProcessors() and pinned byte-for-byte by AtmosphereRuntimeIndexTest.

At runtime, discovery is the union of the classpath scan and every index found via classpath*: — deliberately not “index wins”. An index is per-artifact, and letting one short-circuit the scan let a single jar hide every other jar’s classes.

4.0.63-SNAPSHOT — Run Workflow<S> on Temporal

Section titled “4.0.63-SNAPSHOT — Run Workflow<S> on Temporal”

Workflow.run() now resolves its durable-execution backend through the DurableExecutionProvider ServiceLoader SPI — the in-tree step engine is the always-on fallback, and the new atmosphere-checkpoint-temporal module ships a Temporal adapter behind that seam. Add one dependency and the same workflow runs on a Temporal service: Temporal owns per-step retries, timeouts, and execution history/visibility (your runs appear in the Temporal UI), while Atmosphere keeps the CheckpointStore snapshot trail, hibernation, and cross-restart resume — the two engines write an identical trail and are interchangeable mid-flight. Steps execute as Temporal activities in the calling JVM, so nothing about your state type S needs to become serializable. Availability is runtime truth: an unreachable server is never selected. Proven end-to-end by unit tests on the Temporal test service and a Playwright lane that asserts the run — type, task queue, per-step activities, terminal result — in Temporal’s own Web UI. See the Durable Checkpoints reference.

4.0.62 — Session tape: record agent runs, replay them, watch them in the Console

Section titled “4.0.62 — Session tape: record agent runs, replay them, watch them in the Console”

Flip atmosphere.ai.tape.enabled (off by default) and every streaming AI session records its typed AiEvent stream — as produced at the session boundary — as an append-only, per-run tape: prompts, completions, tool calls, with a late-bound run id and crash-resume segments. The bundled store is bounded in-memory or SQLite-durable; a TapeStore SPI accepts your own.

A recorded run can be reconstructed after the fact with no model call — including a whole multi-agent coordination tree, linked run-to-run by parentRunId. The read surface is admin-gated (REQUIRE_PRINCIPAL, content-read default-deny), and the Atmosphere Console makes it visual: a Tape tab lists recorded runs and their step streams, and replaying a coordinator run renders the coordination tree as an interactive node graph (coordinator → agents; click a node to open that run’s steps). The tab appears only when a recorder is actually installed at runtime — runtime truth, not classpath detection.

Because each completed run is a (prompt → completion) record, the tape doubles as training data: TapeDatasetCli extracts chat-format JSONL for distilling a smaller model. See the Session Tape reference and the Session Tape & Replay tutorial.

4.0.60-SNAPSHOT — Deep-agent harness on by default

Section titled “4.0.60-SNAPSHOT — Deep-agent harness on by default”

Atmosphere agents are now deep agents out of the box. A new harness() attribute — typed by the Harness enum (MEMORY, CACHE, DELEGATION, PLANNING, FILESYSTEM, ALL) — lands on @Agent, @Coordinator, and @AiEndpoint:

  • @Agent and @Coordinator default to {Harness.ALL} — a plain annotation gets conversation memory, long-term memory (facts extracted at session close, recalled on the next connection), a conservative prompt-cache default, a persistent plan surface, a bounded file workspace, and — on a coordinator — the built-in delegate_task tool plus governed fleet dispatch. harness = {} opts a class down to a bare loop.
  • Planning and a virtual filesystem — every tool-calling agent gets the write_todos plan tool plus six file tools (ls, read_file, write_file, edit_file, glob, grep) over a bounded (512 KiB per file, 256 files, 16 MiB total), conversation-scoped workspace store. Plans persist per conversation and stream as plan-update events. Tri-state knobs — the atmosphere.ai.planning / atmosphere.ai.filesystem system properties, with LLM_PLANNING / LLM_FILESYSTEM env fallbacks — pick auto (the default: a native surface wins when the runtime declares AiCapability.PLANNING / VIRTUAL_FILESYSTEM — Embabel, AgentScope, and Spring AI Alibaba plan natively; ADK and Anthropic bridge their own file machinery), builtin, or native. The console gains a Workspace tab — live plan plus file browser — backed by read-only /api/admin/workspace discovery and per-agent plan/file endpoints.
  • @AiEndpoint defaults to {} — bare, with per-endpoint opt-in (harness = {Harness.MEMORY} activates conversation memory even when conversationMemory = false; an explicit true always wins).
  • Tri-state app-wide flagatmosphere.ai.harness.enabled (Spring), quarkus.atmosphere.ai.harness.enabled (Quarkus), or the org.atmosphere.ai.harness.enabled init-param (servlet): unset leaves the annotations in charge, true gives bare @AiEndpoints the full harness too, and false is the operational kill switch that beats every annotation. exclude-paths carves individual endpoint paths out.
  • Runtime truthGET /api/console/info reports a harness block with each primitive’s actual state (ACTIVE / INACTIVE(reason) / CONVENTION), never configuration intent.

See the Harness page for the enum table, precedence rules, per-runtime configuration keys, and the console payload.

4.0.51 — MCP 2026-07-28 release candidate

Section titled “4.0.51 — MCP 2026-07-28 release candidate”

Atmosphere’s MCP server now speaks the 2026-07-28 revision — the largest change to the Model Context Protocol since launch — alongside the session-based protocol it already supported (2024-11-05 through 2025-11-25). It is a stateless dialect chosen per request, so every existing MCP client keeps working unchanged while new clients get:

  • Stateless transport — no session id, no handshake; the server runs behind a plain round-robin load balancer with no session affinity.
  • OperabilityMcp-Method / Mcp-Name routing headers, cacheable tools/list / resources/read (ttlMs, cacheScope), and W3C trace context bridged into OpenTelemetry.
  • Tasks extension — a @McpTool(longRunning = true) call returns a handle the client polls via tasks/get; multi-round-trip lets the server ask for more input mid-call.
  • MCP Apps (SEP-1865) — a tool can ship a ui:// HTML UI that a host renders in a sandboxed iframe. The bundled console is a working host with a bidirectional App Bridge (apps call server tools through the host under governance; the host lists and calls the app’s own tools) and a separate-origin sandbox proxy for isolation.
  • Authorization — the server acts as an OAuth 2.0 Resource Server (RFC 9728 metadata + WWW-Authenticate); a request authenticates via a configured TokenValidator over Authorization: Bearer, or a servlet filter’s principal (e.g. Spring Security). End-to-end tested on the embedded server, Spring Boot, and Quarkus (JVM).

The outbound atmosphere-mcp-client still tracks the official MCP Java SDK and negotiates the session protocol; stateless client negotiation waits on upstream SDK support. See the MCP reference.

4.0.50-SNAPSHOT — Code-as-action sandbox

Section titled “4.0.50-SNAPSHOT — Code-as-action sandbox”

A model can now accomplish a task by writing code rather than negotiating many fine-grained tool calls. The code_exec tool runs that code — bash, JavaScript, or Python — in an isolated, ephemeral container and streams the logs, exit code, and any screenshots back as observations, so the agent iterates: write → run → observe → revise.

  • Default-deny, container-isolated. Code execution is off unless org.atmosphere.ai.code.enabled=true, and the tool is offered only when a container engine is confirmed present at runtime (not merely configured). Each session gets one ephemeral container — --network none by default, non-root, --cap-drop ALL, no-new-privileges, read-only rootfs + a bounded writable workspace, with memory/cpu/pid caps — provisioned lazily and torn down on every terminal path (success, error, cancel, timeout).
  • Live in the Console. When code_exec is enabled the tool-loop ceiling lifts to many write→run→observe rounds, and each round streams an agent-step event plus any screenshots the code produced — rendered inline in the Atmosphere Console as you watch.
  • spring-boot-browser-agent sample. The agent drives a headless browser with Playwright in the sandbox and streams the page screenshots back live (Cohere-backed; requires Docker).

Executing model-written code is the largest boundary Atmosphere exposes. It is opt-in, container-isolated, and default-deny — choose the network policy deliberately, pin the image, and size the resource caps before enabling it in production.

4.0.49-SNAPSHOT — Event-sourced coordination journal

Section titled “4.0.49-SNAPSHOT — Event-sourced coordination journal”

The coordinator gains a full event-sourced runtime contract — every CoordinationJournal event now carries causal lineage in an EventEnvelope(eventId, parentEventId, event), and four additive primitives let consumers project, persist, and branch coordinations without breaking the existing journal surface.

  • Causal lineage. JournalingAgentFleet threads parent IDs through every parallel() / pipeline() / route() / proxy.call() dispatch path: CoordinationStartedAgentDispatchedAgentCompleted/AgentFailedAgentEvaluated. Legacy journal.record(event) callers continue to work unchanged — events get wrapped as root envelopes with no parent.
  • CoordinationProjection.from(journal, coordinationId). Pure read-only causal DAG built from the stored envelopes. Exposes roots(), children(eventId), walk(visitor), agents(), failedDispatches(), evaluations(). No execution, no LLM, no side effects — useful for debugging tools and post-hoc analysis.
  • FileCoordinationJournal(Path). Append-only NDJSON file backend. One JSON object per line; replays on start() into an in-memory index for queries; tolerates a truncated final line from a JVM kill mid-append; single-writer locked appends. Polymorphic ser/deser of the sealed CoordinationEvent hierarchy via a Jackson 3 mix-in so the event records themselves stay annotation-free.
  • CoordinationFork + ForkCreated event. What-if branching: fork.from(coordId, eventId).reason(...).with(altCall).execute(fleet) creates a new coordination, records a ForkCreated envelope linking back to the parent event, and runs the alternate via JournalingAgentFleet.withCoordinationId(...). The parent coordination is immutable; the fork is a peer with its own future.

Backed by 38 tests including a three-process integration test that runs a parallel coordination, replays from disk on restart, projects the DAG, forks an alternate, replays again, and verifies both branches survive. See the Coordinator reference for the full surface.

4.0.46-SNAPSHOT — Enterprise console + capability parity

Section titled “4.0.46-SNAPSHOT — Enterprise console + capability parity”

The current development line closes the seven gist gaps that the feat/ai-gap-fixes review flagged. Highlights:

  • Spring AI Alibaba: unconditional TOOL_CALLING / TOOL_APPROVAL / TOKEN_USAGE. UsageCapturingChatModel wraps the configured Spring AI ChatModel bean at auto-configuration time; the per-thread accumulator captures ChatResponseMetadata.getUsage() across every step of the ReAct graph and emits one TokenUsage record per dispatch. Tool calling is no longer gated on staticChatModel != nullSpringAiAlibabaToolBridge runs on every tool-bearing request. Token-based AiBudget breaches now trip uniformly alongside wall-clock budgets.
  • RAG vector-store matrix. Three new direct connectors — PgVectorContextProvider (JDBC + pgvector), QdrantContextProvider (REST), PineconeContextProvider (REST) — ship as zero-dep alternatives to the Spring AI / LangChain4j SPI bridges. See RAG reference for the full matrix including Weaviate, Milvus, Chroma, Elasticsearch, Redis Stack, MongoDB Atlas, OpenSearch, and Cassandra reachable via the bridges.
  • Workflow authoring inside the admin control plane. New WorkflowManifest + WorkflowStore SPI + WorkflowController plus a vanilla-JS authoring UI at /atmosphere/admin/workflow.html. Saves through ControlAuthorizer + audit log; optimistic concurrency via version field rejects stale writes with 409.
  • Eval dashboard inside the admin control plane. New EvalRun + EvalRunStore SPI + EvalController plus dashboard UI at /atmosphere/admin/evals.html that aggregates pass-rate per GoldenEvalBaseline and tabulates recent runs submitted by CI.
  • atmosphere-admin-bundle single-dep aggregator. One Maven dependency pulls in spring-boot-starter + admin + ai + coordinator + agent + rag + checkpoint + durable-sessions, giving operators the dashboard, journal flow viewer, workflow authoring, eval dashboard, and governance decision viewer in a single drop-in artifact.
  • Five flagship templates promoted (rag, ai-tools, guarded-agent, coding-agent, ms-governance) in samples/README.md and cli/README.md — the canonical enterprise agent shapes most teams reach for first.
  • docs/runtime-selection.md decision tree. Question-by-question walkthrough for picking among the twelve AgentRuntime adapters, mirrored on the website at Runtime Selection.
  • Cross-tab @AiEndpoint isolation fixAiEndpointHandler.onRequest now dispatches POST/frame prompts to the originating client only, routing via SUSPENDED_ATMOSPHERE_RESOURCE_UUID (WebSocket) or X-Atmosphere-tracking-id (SSE / long-polling). Pre-fix, the handler called broadcaster.broadcast(msg) on the per-path broadcaster, so two open Console tabs each received both prompts. Pinned by 15 Playwright cases driving real Chromium with two browser contexts (every AI-shaped sample with a Console UI), plus contract tests in AiEndpointHandlerCrossTabIsolationTest.
  • Bundled Atmosphere Console auto-detects ai vs. broadcast mode/api/console/info adds a mode field and the Vue frontend swaps empty-state copy + default subtitle. @ManagedService chats (spring-boot-mcp-server, spring-boot-otel-chat) now read “Multi-client broadcast chat” instead of borrowing the AI-assistant copy. Detection is class-name based (org.atmosphere.{ai,agent,coordinator}.* → ai, everything else → broadcast) so it stays compile-time independent of modules/ai and modules/agent.
  • Quarkus parity for /api/console/info — new AtmosphereConsoleInfoServlet (registered via registerConsoleInfoServlet build step in AtmosphereProcessor) gives Quarkus apps the same subtitle / endpoint / runtime / mode payload Spring Boot apps get. Two new config keys — quarkus.atmosphere.console-subtitle and quarkus.atmosphere.console-endpoint — mirror the Spring side.

@Agent + @Command — one annotation, every channel

Section titled “@Agent + @Command — one annotation, every channel”
  • @Agent is the single entry point that wires @AiEndpoint, commands, tools, skill files, conversation memory, and multi-protocol exposure (MCP, A2A, AG-UI) based on classpath detection. Conversation memory is on by default. See @Agent.
  • @Command defines slash commands once and routes them across Web (WebSocket), Slack, Telegram, Discord, WhatsApp, and Messenger when atmosphere-channels is on the classpath. Confirmation flow for destructive actions and auto-generated /help are included.
  • skill.md files act as both the LLM system prompt and agent metadata. Sections like ## Skills, ## Tools, ## Channels, and ## Guardrails are parsed into A2A Agent Cards, MCP tool manifests, and channel validation. See Skills.
  • atmosphere-agent is the module hosting the annotation processor, CommandRouter, SkillFileParser, and AgentHandler.

AgentRuntime SPI — the Servlet model for AI agents

Section titled “AgentRuntime SPI — the Servlet model for AI agents”
  • AgentRuntime replaces the earlier AiSupport SPI. It dispatches the entire agent loop — tool calling, memory, RAG, retries — to whichever AI framework is on the classpath. Write your @Agent once, run it on any runtime. Switch runtimes by changing a single Maven dependency.
  • Twelve runtimes share a unified capability baseline (text streaming, structured output, progress events, conversation memory, per-request retry): Built-in, LangChain4j, Spring AI, Google ADK, Embabel, JetBrains Koog, Microsoft Semantic Kernel, Alibaba AgentScope, Spring AI Alibaba, Anthropic, Cohere, and CrewAI (CrewAI via an out-of-process Python sidecar, the first non-Java adapter in the project). Tool calling now reaches all twelve runtimes — each ships a dedicated tool bridge (AgentScopeToolBridge, SpringAiAlibabaToolBridge, and the CrewAI ToolCallbackServer close the matrix) that routes every invocation through ToolExecutionHelper.executeWithApproval. The built-in runtime gained full OpenAI-compatible tool calling (max 5 rounds), so @AiTool works with zero framework dependencies.
  • Auto-detection via ServiceLoader — the highest-priority() runtime that reports isAvailable() wins. The AI Console subtitle and /api/console/info report the active runtime.
  • Usage metadata (ai.tokens.input, ai.tokens.output, ai.tokens.total) is reported by every runtime that exposes it, and flows into MicrometerAiMetrics.
  • AiCapability negotiation@AiEndpoint(requires = {TOOL_CALLING}) fails fast at startup if the active runtime can’t satisfy required capabilities.

Orchestration primitives for multi-agent systems

Section titled “Orchestration primitives for multi-agent systems”
  • @Coordinator + @Fleet + @AgentRef — declarative multi-agent coordinators. Parallel fan-out, sequential pipelines, optional agents, weighted routing, and circular-dependency detection are built in. See @Coordinator.
  • AgentFleet API — injected into @Prompt methods. fleet.parallel(...) fans out concurrently; fleet.pipeline(...) chains sequentially. Results are returned as AgentResult records with text, metadata, duration, and success status.
  • Local + Remote transport — coordinators transparently call local agents via direct invocation or remote agents via A2A JSON-RPC. The AgentProxy abstraction hides the transport layer.
  • Agent handoffssession.handoff("billing", message) transfers a conversation with its full history, with a cycle guard and an AiEvent.Handoff emitted for observability.
  • Approval gates@RequiresApproval parks the virtual thread until a client approves or denies the action via the /__approval/ protocol.
  • Conditional routingfleet.route(result, spec) uses first-match evaluation with journal recording.
  • Long-term memoryLongTermMemoryInterceptor with pluggable extraction strategies (on-session-close, per-message, periodic).
  • Eval assertionsLlmJudge exposes meetsIntent(), isGroundedIn(), and hasQuality() for LLM-as-judge testing.
  • AiEvent sealed interface — 15 structured event types (TextDelta, ToolStart, ToolResult, AgentStep, EntityStart, StructuredField, Handoff, and more) delivered via StreamingSession.emit(), powering rich real-time UIs.
  • @AiTool framework-agnostic tool calling — declare tools once with @AiTool/@Param, portable across every backend via bridge adapters (SpringAiToolBridge, LangChain4jToolBridge, AdkToolBridge, AtmosphereToolBridge for Koog). ToolRegistry.execute(name, args, session) auto-emits ToolStart/ToolResult through the streaming session.
  • Per-endpoint model override@AiEndpoint(model = "gpt-4o") selects a model per endpoint without touching global config.
  • Multi-backend routing@AiEndpoint(fallbackStrategy = FAILOVER) wires DefaultModelRouter for failover, round-robin, or content-based routing.
  • Auto-detected ConversationPersistenceconversationMemory = true discovers Redis or SQLite backends via ServiceLoader; falls back to in-memory.
  • Memory strategies — pluggable MemoryStrategy SPI with MessageWindowStrategy, TokenWindowStrategy, and SummarizingStrategy.
  • StructuredOutputParser SPI — generate JSON Schema instructions from Java classes, parse LLM output into typed objects. JacksonStructuredOutputParser works with any model.
  • Enhanced RAGContextProvider.transformQuery(), filter(), rerank(), and postProcess() cover query rewriting, metadata/tenant filtering, result re-ranking, and final context shaping without a custom pipeline. Prompt injection uses ContextProvider.formatCitation() so chunk metadata (source_document, chunk_index, chunk_start, chunk_end) is visible to the model; InMemoryContextProvider gives a zero-dependency provider for development.
  • First-class identity fieldsAiRequest carries userId, sessionId, agentId, and conversationId as explicit fields instead of an untyped hints() map.
  • AiMetrics SPIMetricsCapturingSession records first-streaming-text latency, streaming text usage, and errors via a pluggable, ServiceLoader- discovered AiMetrics interface.
  • Cache replay coalescing — reconnecting clients receive coalesced missed streaming texts in a single batch.
  • Streaming text budget managementStreamingTextBudgetManager enforces per-session and per-endpoint limits.
  • Cost metering UI — per-message cost badges in the chat frontend via StreamingSession request attributes.
  • atmosphere-ai-testAiTestClient, AiResponse, and fluent AiAssertions for testing AI endpoints in JUnit 5. See AI Testing.

Introduced in 4.0.40. A declarative layer over the guardrail SPI plus the wire surfaces, samples, and CI gates that make it adoptable. See the governance reference for the full story.

  • GovernancePolicy SPI — admit / transform / deny vocabulary aligned with OPA/Rego and Microsoft Agent Governance Toolkit; stable identity (name / source / version) for audit-trail pinning.
  • YAML PolicyParser (default) — drop atmosphere-policies.yaml on the classpath, restart, governance changes. Built-in types: pii-redaction, cost-ceiling, output-length-zscore, deny-list, allow-list, message-length, rate-limit, concurrency-limit, time-window, metadata-presence, authorization. SnakeYAML declared as an explicit runtime dep so bare-JVM and Quarkus deployments get the parser out-of-the-box.
  • Microsoft schema parityYamlPolicyParser auto-detects MS Agent Governance Toolkit YAML (top-level rules: sequence) and produces an MsAgentOsPolicy honoring all nine operators (eq/ne/gt/lt/gte/lte/in/contains/matches) and four actions (allow/deny/audit/block). Conformance tests load MS’s own examples byte-for-byte.
  • Optional plug-in parsersatmosphere-ai-policy-rego (OPA, shells to opa eval) and atmosphere-ai-policy-cedar (AWS, shells to cedar authorize or plugs in cedar-java).
  • @AgentScope annotation — declarative purpose + forbidden topics per @AiEndpoint. Three tiers: rule-based (sub-ms, ships with built-in hijacking probes for code / medical / legal / financial), embedding-similarity (default), and LLM-classifier (opt-in for high-stakes scopes). Breach behavior: POLITE_REDIRECT / DENY / CUSTOM_MESSAGE.
  • System-prompt hardeningAiPipeline prepends an unbypassable scope-confinement preamble to every execute() call so a sample author can’t accidentally drop it.
  • Sample-hygiene CI lintSampleAgentScopeLintTest walks samples/ and fails the build on any @AiEndpoint or @Coordinator missing @AgentScope (or lacking a non-blank justification when unrestricted = true). 12 existing endpoints retrofitted.
  • ScopePolicy.postResponseCheck — re-classify the streamed response against the declared purpose; OUT_OF_SCOPE responses become Deny with a post-response: prefix.
  • Per-request scope install — interceptors can write a ScopeConfig for a single turn (one @AiEndpoint hosts four classroom personas, each with its own scope).
  • PolicyAdmissionGate.admitToolCallToolExecutionHelper consults the gate on every @AiTool dispatch. The canonical MS rule {field: tool_name, operator: eq, value: drop_database, action: deny} fires before the executor runs. OWASP A02 (Tool Misuse): COVERED.
  • Static verification of LLM-emitted tool-call workflows — the LLM emits a JSON workflow describing the entire intended sequence; a deterministic verifier chain runs over the AST against a declarative Policy; only verified plans dispatch. Atmosphere’s implementation of Erik Meijer’s Guardians of the Agents pattern (CACM, January 2026), modelled on the metareflection/guardians Python reference implementation.
  • Six built-in verifiers auto-discovered via ServiceLoader: AllowlistVerifier (priority 10) catches deployment drift between policy and registry; WellFormednessVerifier (20) blocks forward binding references; CapabilityVerifier (25) enforces least-authority via @RequiresCapability grants; TaintVerifier (30) refuses dataflow into @Sink-marked parameters incl. transitive flow; AutomatonVerifier (40) executes plans against SecurityAutomaton sequences; SmtVerifier (200) proves numeric invariants over symbolic tool-call data flow via the SmtChecker SPI — a real SMT backend ships as atmosphere-verifier-smt (SMTInterpol pure-JVM default, Z3 opt-in; the no-op default applies only when that module is absent).
  • Co-located policy@Sink(forbidden = {"fetch_emails"}) on a tool parameter is the entire dataflow declaration; SinkScanner derives the TaintRule at startup. Renaming a tool or parameter without updating both ends is impossible because the rule travels with the code.
  • PlanAndVerify orchestrator runs the runtime in plan mode (empty tool list, LLM emits JSON), parses via WorkflowJsonParser, runs the verifier chain via VerificationResult.merge, and dispatches via WorkflowExecutor only on green. Refusal throws PlanVerificationException carrying the offending workflow plus the full violation list — and crucially, no tool fires on that path.
  • verify CLI — offline plan inspection against any policy JSON, exits 0/1/2 for shell pipelines and CI corpora.
  • Sample: spring-boot-guarded-email-agent runs the canonical inbox-exfiltration scenario end-to-end; the malicious goal is refused with a typed taint violation on steps[1].arguments.body. Spring Boot test + 6 Playwright e2e tests pin the headline guarantee.
  • AbstractAgentRuntimeContractTest.policyDenyBlocksRuntimeExecute is inherited by all twelve runtime adapters (Built-in, Spring AI, LangChain4j, ADK, Embabel, Koog, Semantic Kernel, AgentScope, Spring AI Alibaba, Anthropic, Cohere, CrewAI). The “deny before runtime” guarantee is a build-time invariant for each runtime adapter; a regression breaks the build, not production.
  • Ed25519-signed commitment records (@Experimental) — extend W3C Verifiable Credentials + Google AP2 delegated-authority semantics to cross-agent dispatch logs. Emitted from JournalingAgentFleet when a signer is installed.
  • Flag-off by defaultatmosphere.ai.governance.commitment-records.enabled=false. Schema is subject to revision while the W3C CCG / AP2 / Visa TAP standards-track convergence settles; opt-in operators acknowledge potential migration.
  • Self-assessment matrices — OWASP Agentic Top 10 (Dec 2025) plus EU AI Act / HIPAA / SOC2 mappings live in OwaspAgenticMatrix and ComplianceMatrix. Each row carries evidence class, test class, and a consumer-grep pattern.
  • EvidenceConsumerGrepPinTest — walks src/main under modules + samples and fails the build if any row claims coverage with no production consumer. No marketing-grade overclaim survives a CI run.
  • agt verify-shaped JSON export at GET /api/admin/governance/agt-verify — wire-compatible with Microsoft Agent Compliance so cross-vendor compliance pipelines round-trip both.
  • GovernanceDecisionLog — thread-safe ring buffer (default 500 entries) with redaction-safe context snapshots (truncated message, primitive-only metadata). Surfaced at GET /api/admin/governance/decisions.
  • AuditSink SPI + AsyncAuditSink — bounded drop-on-full queue so the admission thread never blocks on IO. Two reference modules ship: atmosphere-ai-audit-kafka and atmosphere-ai-audit-postgres (JSONB on Postgres, CLOB elsewhere; works against any DataSource). JSON shape matches MS Agent Governance Toolkit’s audit_entry.
  • 12 governance endpoints under /api/admin/governance/ — read endpoints (policies, summary, health, decisions, owasp, compliance, agt-verify, commitments) and write endpoints (check, reload, kill-switch/{arm,disarm}).
  • Triple-gate authorization — feature flag → Principal → ControlAuthorizer. Spring Boot and Quarkus ship symmetric implementations; Quarkus adds a fourth principal source (constant-time-compared X-Atmosphere-Auth token) for ops tooling not yet on Jakarta Security.
  • Admin Console tabs — three Vue views (Policies, Decisions, OWASP) poll the read endpoints on live intervals; tabs auto-hide when governance is not installed.
  • spring-boot-ms-governance-chat — chat gated by Microsoft Agent Governance Toolkit YAML, verbatim. Demonstrates 9 MS-schema rules (destructive SQL, legal/media/exec escalation, PII shapes, password disclosure, discount-limit enforcement) plus @AgentScope for customer-support confinement.
  • WebTransport over HTTP/3 — Atmosphere now ships an HTTP/3 + WebTransport transport, sitting alongside WebSocket, SSE, long-polling, and gRPC on the same Broadcaster. See WebTransport Reference.
  • gRPC transport — bidirectional streaming on the same Broadcaster as the classic transports.
  • Virtual threads on by defaultExecutorsFactory uses Executors.newVirtualThreadPerTaskExecutor(), and DefaultBroadcaster plus 16 other core classes migrated from synchronized blocks to ReentrantLock to avoid pinning. Opt out with ApplicationConfig.USE_VIRTUAL_THREADS=false.
  • Rooms & presenceRoomManager with join/leave, presence events, message history, AI virtual members, and a room protocol backed by sealed records (Join, Leave, Broadcast, Direct).
  • RawMessage API — first-class public wrapper for pre-encoded messages that bypass @Message decoder/encoder pipelines, used by the room protocol to avoid JSON envelope mangling. ManagedAtmosphereHandler.Managed is deprecated in favor of RawMessage.
  • BackpressureBackpressureInterceptor protects against slow clients with a configurable high-water mark (default 1000 pending messages) and drop-oldest, drop-newest, or disconnect policies.
  • Clustering — Redis (Lettuce 6.x, non-blocking pub/sub) and Kafka broadcasters for multi-node deployments.
  • Durable sessions — survive restarts with InMemory, SQLite, or Redis-backed SessionStore implementations; room memberships and broadcaster subscriptions are restored on reconnection.
  • Micrometer metrics (AtmosphereMetrics) — gauges, counters, and timers for active connections, broadcasters, broadcast latency, room-level gauges, cache hit/miss/eviction, and backpressure drop/disconnect.
  • OpenTelemetry tracing (AtmosphereTracing) — per-request spans with atmosphere.resource.uuid, atmosphere.transport, atmosphere.action, atmosphere.broadcaster, and atmosphere.room attributes.
  • Health check (AtmosphereHealth) — framework-level snapshot exposed via the Spring Boot Actuator AtmosphereHealthIndicator.
  • MDC interceptor — sets atmosphere.uuid, atmosphere.transport, and atmosphere.broadcaster in the SLF4J MDC for structured logging.
  • Governance policy plane — declarative GovernancePolicy SPI layered on top of AiGuardrail. YamlPolicyParser loads Atmosphere-native (policies: / type:) or Microsoft Agent Governance Toolkit (rules: / condition:) YAML verbatim — all nine MS operators and four actions ported faithfully, conformance pinned against MS’s own example YAMLs. PolicyAdmissionGate extends governance to non-pipeline code paths; GovernanceController exposes /api/admin/governance/policies, /summary, and a Microsoft-/check-compatible decision endpoint so external gateways (Envoy, Kong, Azure APIM) can point at Atmosphere as their policy provider without code changes. See Governance Policy Plane tutorial and reference.
  • Spring Boot 4.0.7 — auto-configuration, Actuator health indicator (AtmosphereHealthIndicator), and two separate pieces of native image support: AtmosphereRuntimeHints registers reflection and resource hints sourced from NativeImageMetadata.collect(…) rather than a hand-maintained list, and AtmosphereAnnotationScanAotProcessor (registered in META-INF/spring/aot.factories) resolves Atmosphere’s annotations during AOT and records them for the runtime to read. Hints alone are not enough — without the AOT scan every annotated endpoint goes undiscovered in a native image. Scope of what is verified is in the 4.0.65-SNAPSHOT section above. Spring Boot 4.0 is modularized, so the starter now depends explicitly on spring-boot-servlet, spring-boot-web-server, and spring-boot-health where needed. The starter overrides the parent POM’s old SLF4J 1.x/Logback 1.2.x pins in <dependencies> so upgrades don’t regress. See Spring Boot Reference.
  • Quarkus 3.36.0 — build-time Jandex annotation scanning, Arc CDI integration, custom QuarkusJSR356AsyncSupport, and @BuildStep-driven native image registration. Registration is driven by the Jandex index plus NativeImageMetadata.collect(…), not by configuration: registerReflection, registerPoolReflection and registerServiceResources produce the reflective classes and resources, and registerEncoderDecoderClasses walks the index for @Message(encoders/decoders) and @Ready(encoders) so classes named only inside an annotation survive the image. quarkus.atmosphere.* configures the extension itself (servlet mapping, loadOnStartup). Scope of what is verified is in the 4.0.65-SNAPSHOT section above. See Quarkus Reference.
  • Kotlin DSLatmosphere { ... } builder and coroutine extensions (broadcastSuspend, writeSuspend). Requires Kotlin 2.1+.
  • atmosphere-channels — bridges @Agent to Slack, Telegram, Discord, WhatsApp, and Messenger with zero per-channel code. ChannelFilter chain for message processing, plus built-in MessageSplittingFilter (auto-truncates to channel max length) and AuditLoggingFilter.
  • MCP server — expose tools, resources, and prompt templates to AI agents with @McpTool / @McpResource / @McpPrompt annotations on any class marked @Agent (there is no dedicated @McpServer annotation — the MCP module reuses @Agent from atmosphere-agent). Supports Streamable HTTP (MCP 2025-11-25 spec), WebSocket, or SSE, with a stdio bridge for Claude Desktop and a programmatic McpRegistry API. See MCP Reference.
  • OpenTelemetry tracingMcpTracing auto-instruments tool, resource, and prompt calls with span propagation.
  • atmosphere.js 5.0.24 — TypeScript client with no runtime dependencies. ESM + CJS + IIFE bundles, WebSocket with configurable fallback to SSE, HTTP streaming, or long-polling. See atmosphere.js.
  • React, Vue, Svelte hooksuseAtmosphere, useRoom, usePresence, useStreaming, and AI-SDK-style chat state via useChat / createChatStore. Shared chat components ship through atmosphere.js/chat.
  • React Native / ExpouseAtmosphereRN, useStreamingRN, and useChatRN with an EventSource polyfill, NetInfo injection, and markdown rendering for mobile AI chat. See React Native.
  • wAsync 4.0 — the Java client rewritten on java.net.http with gRPC support. See Java Client.

Atmosphere 4.0 ships with a wide set of runnable samples covering every major feature area — real-time chat, AI streaming with multiple runtime adapters, tool calling, multi-agent orchestration, MCP, RAG, clustering, durable sessions, and channel integrations. The full catalogue lives at samples/ on GitHub. Highlights:

SampleFeature area
spring-boot-ai-chatStreaming AI chat via the AgentRuntime SPI (auto-selects runtime adapter)
spring-boot-ai-toolsPortable @AiTool tool calling across all runtimes
spring-boot-ai-classroomMulti-room AI with a React Native / Expo client
spring-boot-rag-chatRetrieval-augmented generation with ContextProvider
spring-boot-mcp-serverMCP server exposing tools, resources, and prompts
spring-boot-a2a-agentA2A protocol agent-to-agent communication
spring-boot-agui-chatAG-UI protocol with progressive UI streaming
spring-boot-dentist-agentDr. Molar emergency dental agent with Slack + Telegram channels
spring-boot-multi-agent-startup-team@Coordinator multi-agent workflow
spring-boot-checkpoint-agentDurable HITL workflow with CheckpointStore
spring-boot-orchestration-demoSupport desk with live handoff and @RequiresApproval
spring-boot-durable-sessionsSession persistence across restarts
spring-boot-channels-chatMulti-channel (Slack/Telegram/Discord/WhatsApp/Messenger) chat
spring-boot-otel-chatOpenTelemetry tracing with Jaeger
spring-boot-ms-governance-chatMicrosoft Agent Governance Toolkit demo with @AgentScope policy chain
spring-boot-coding-agentSandboxed coding agent — clones a repo, reads files, proposes a patch
spring-boot-browser-agentCode-as-action agent — the model writes Playwright driving a headless browser in an isolated sandbox container; screenshots stream to the Console live (requires Docker)
spring-boot-guarded-email-agentPlan-and-Verify (atmosphere-verifier) inbox-exfiltration demo
spring-boot-personal-assistantLong-lived @Coordinator assistant with memory + delegation
spring-boot-reattach-harnessMid-stream reattach harness (@AiEndpoint reattach contract)
quarkus-chatQuarkus extension chat
quarkus-ai-chatFive @AiEndpoint demos on Quarkus + LangChain4j bridge (port 18810)
spring-boot-chatReal-time WebSocket chat with Spring Boot
grpc-chatStandalone gRPC transport
chatClassic Atmosphere chat (WAR deployment)
embedded-jetty-websocket-chatEmbedded Jetty WebSocket chat (no framework)
  • Architectural validation — CI gate detects NOOP/dead code, placeholder stubs, DI bypass, and fluent builder misuse via TOML-configured patterns.
  • atmosphere-generator — CLI scaffolding with --tools flag to generate @AiTool methods.
  • 24-chapter tutorial — the full tutorial book at Chapter 1: Introduction walks from “install the CLI” through AI, MCP, clustering, and multi-channel deployment.

Heads up before you upgrade:

  • Token → Streaming Text rename (4.0.11). Every AI API, javadoc entry, and atmosphere.js client surface moved from “token” to “streaming text” to describe LLM output chunks. onTokenonStreamingText, totalTokenstotalStreamingTexts, and the wire protocol message type changed from "token" to "streaming-text". This is a breaking change for atmosphere.js consumers and custom AiStreamBroadcastFilter implementations.
  • Jackson 3.1.1 migration. The runtime now depends on Jackson 3.x, which moved its packages from com.fasterxml.jackson to tools.jackson. Custom JacksonEncoder / JacksonDecoder subclasses, any filters that construct ObjectMapper directly, and any integration code importing from com.fasterxml.jackson.* need to be updated.
  • AiSupportAgentRuntime. Code that implemented the legacy AiSupport SPI should migrate to AgentRuntime. The capability baseline, tool calling, and usage metadata contracts are now unified across all twelve runtimes.
  • WebSocket HTML sanitization (4.0.11). HTML sanitization was disabled for the WebSocket transport because encoding JSON in WebSocket frames broke the AI streaming wire protocol. HTTP transports continue to sanitize write methods, and cookies over HTTPS now default to Secure.
  • JDK 21 minimum. No Java 8/11/17, no javax.servlet, no legacy app servers (GlassFish 3/4, Jetty 6-11, Tomcat 6-10, WebLogic, JBoss AS 7, or Netty/Play/Vert.x integrations).
  • atmosphere.js package rename. The npm package is atmosphere.js (no jQuery dependency). Update imports to import { atmosphere } from 'atmosphere.js'.