All notable changes to the Atmosphere Framework are documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
- every member of a broadcastReply room sees the prompts the others type
- a page reloaded mid-answer reattaches to its AI run
- name the timeout cancel reason in the client type and the Console
- add a cancellable model call to the reattach harness
- produce the application's AiEnvironment as a CDI bean
- a Clear before the first token discards this client's room turn, not another member's
- a room prompt is echoed only from the admission of the turn that streams it
- a reattached run streams like a turn the page started
- Expo classroom derives the streamed reply instead of copying it per token
- a handler a failed registration leaves unregistered lets go of its sweeper and timer holds
- endpoints hold the sweeper and grace timer from construction; none restarts unheld
- every way a reattached client stops listening decides for the run, once
- an endpoint's destroy cancels only the reattach graces of the runs it started
- an endpoint's destroy ends its own left-open runs and stops the sweeper only when unheld
- a reattached connection departing ends the run only once the one it started on is gone
- bound runs left open after their @Prompt returns and reach them after a reattach
- a run whose @Prompt returns with its session open ends with that session
- a room run ends for the room when its prompter leaves, its grace expires or the run ends
- show the working tabs and no chat when the app serves no chat endpoint
- redirect an unserved GET / to the Console with or without AI
- log an absent actuator on one DEBUG line, stack at TRACE
- advertise a chat endpoint only when a handler serves it
- warn once per provider about a missing VectorStore, then log at DEBUG
- a room member's reattach replays only the run events before it rejoined
- the same user reattaching under a new tracking id owns its room run
- a broadcastReply room run keeps broadcasting after its prompter's connection goes
- a room run remembers as many replay positions as the room takes members
- a refused run reattach warns once per run and tracking id, then logs at DEBUG
- a WebSocket or SSE room member reconnecting with the run id gets each later frame once
- only a room run's own client restarts or holds off its reattach grace
- a broadcastReply room member's waiting run-id poll holds the reattach grace off again
- a broadcastReply room member's run-id poll no longer waits on the run
- room members' long-polling replies never make a run forget a client that polled with its id
- a long-polling client's run replay keeps the frames it missed before a later one reached it
- long-polling room replies under shared listeners; own replies end the run replay
- route the 15 s dashboard tick through the same no-overlap refresh
- give every Console form field an id and a name
- label lone tool calls as Tool Calls; name the model in connect status
- report a WebTransport sample ready only once its HTTP/3 server started
- wait for a WebTransport sidecar that is still starting instead of staying on WebSocket
- join rooms and topics with the suspended connection, not a per-frame resource
- serve the agent card at agent-card.json with absolute interface URLs
- name SendMessage in the unauthenticated-endpoint warning
- report no cost for a model the ai-tools rate table does not list
- start a SQLite store once and name the in-memory default as the bean
- warn of the empty default ContextProvider only when no endpoint wired one
- state the in-scope rule before quoting the scope redirect in the preamble
- report an expected policy or guardrail denial without an ERROR stack trace
- log an unloadable SMT solver on one DEBUG line, stack at TRACE
- boot passivation-agent without the AI auto-config its runtime never uses
- stop team-rooms logging raw chat text that can carry secrets
- track handed-out runtimes by identity so an equal instance still hears of the close
- run every AI environment close step when one throws a checked exception it does not declare
- drop a closed runtime's built client and build clients outside the close lock
- finish every step of an AI environment close when a runtime close fails
- close the runtime and embedding instances an AI environment loaded when it closes
- open no AI environment for an intent routing that brings its own decision model
- let a shutdown hook be registered while destroy runs the hooks
- report the long-term-memory screen tier the endpoint's interceptor actually runs
- open no AI environment for a framework that was already destroyed
- build the per-application LLM tiers through forEnvironment factories
- screen a hand-built streaming session's request scope with its framework's application
- admit a request scope with the framework's own AI environment
- resolve scope, injection, moderation and intent tiers per application
- pin the reattach harness Console endpoint through ai.path on both starters
- keep the reattach harness on Tomcat 10.1 core under Spring Boot 3
- hand a long-polling client its run id at once, not with the finished reply
- read an atmosphere.js WebTransport close as a leave in either arrival order
- report a WebTransport session the page left with its stream open as going-away
- run a prompt on a connection only once its @Ready has run
- answer prompts and slash commands of a transport=streaming client
- fail the start when the application's AiEnvironment bean is not application-lived
- offer the Quarkus model to the application's AiEnvironment
- explain an AI-state read only by an allowlist match that covers the read
- publish atmosphere.js only after the Maven release, unless the run is js-only
- wait for the room member to receive the frame an @Prompt sent before asserting it
- a dotted library key is not a Maven goal; atmosphere.js core cap 56KB
- clear sessionStorage before each test
- publish the CLI archive to SDKMAN after each GitHub release
- a reattach's departure only drops the session's registration under it
- pin the idle sweep reaching left-open runs through the run map
- age the post-return lifetime directly; credit the run, not the reattach, for the sweep
- a waiting room poll's grace test arms the grace once its poll is built
- attach the solver-context Javadoc to its method
- pin each path that frees a client's run replay positions
- only a long-polling client leaving for good walks the runs, and once
- pin room run bound overrides and freed waiting slots
- room members polling with the run id take replay positions past the receipt bound
- a run buffer's replay-position bound also bounds the replies it remembers
- name the room frames a run replay re-sends and the runs the per-run bounds apply to
- a run an AI endpoint starts carries its application's long-polling bounds and its own id
- give the expired-piece replay test a parked-reply TTL a sweep cannot race
- a destroyed broadcaster leaves no long-polling room behind
- assert room joins log no unsuspended resource and Console fields carry id/name
- coalesce the live-event dashboard refresh instead of three requests per event
- say team-rooms picks the Console room with atmosphere.console-endpoint
- say what the new AbstractAgentRuntime methods change for older subclasses
- say the environment-close hook runs once, at close or when an instance is not kept
- call onEnvironmentClose on runtimes at AI environment close, not close()
- state what the new runtime close() changes for implementations written before it
- assert the embedding HTTP client terminates when its AI environment closes
- pin that a closed application's guardrails never reach a running one
- pin that an environment whose shutdown hook came too late closes at once
- stub one embedding per input and assert the RAG screen's embedding verdict
- allow CDI's @Dependent and Quarkus LangChain4j's @ModelName in the doc-symbol gate
- pin that an uninterrupted long-polling AI reply arrives once
- browser-verify the AI reattach grace across a page reload
- name WebTransport among the transports whose page reload gets the reattach grace
- check a second framework's LangChain4j runtime has no Quarkus model
- name the CDI container as what uninstalls the knobs after a failed start
- pin that a second application does not inherit the Quarkus model
- deprecate the static AI readers and binders; samples read their own AiEnvironment
- give each application its own native clients in every runtime adapter
- give each application its own AI knobs, settings and runtime instances
- enforce both an explicit skill scopeTier and a restrictive @AgentScope, stricter wins
- let one ScopePolicy enforce several scope legs that a request must all pass
- mark the pagehide close beacon going-away, keep close() a leave
- give a page reload over SSE, long-polling or streaming the reattach grace
- mark the disconnect of a close message whose page is going away
- let an annotation processor fail the framework init instead of being skipped
- keep a run going for a reattach grace after its client loses the connection
- end a run cut short with one cancelled frame naming why, on every path and bridge
- honour atmosphere.ai.* knobs from Spring and Quarkus config and select the runtime by name
- shut down the clients routing rules build for their own endpoint
- count each AI-state read and flag Kotlin imports, not constant imports
- build a routing rule's own client with its context's cache-key and logprobs modes
- shut down an environment's built client after a client was installed over it
- flag the process default, split-line reads and resolver static imports in the AI-state gate
- summarize, rerank and spawn subagents on the runtime of their own application
- offer the auto-configured executor and model so an executor the application sets wins
- keep a runtime instance with its application after that application resets its resolution
- have AgentRuntimeResolver.hasExplicitClientBinding read the calling application
- report each application's own runtime in console, admin and interactions
- resolve decision models, memory, caches and evaluators per application
- shut down the HTTP clients of the settings an AI environment built when it closes
- bind a runtime's application to the calling thread in execute as executeWithHandle does
- resolve the running application's embedding runtimes through EmbeddingRuntimeResolver
- stop the LLM_* environment fallback from replacing settings or publishing them per request
- keep a workspace RUNTIME.md's generation values on its own settings
- keep the prompt-cache-key and logprobs modes an OpenAI-compatible client was built with
- stop counting the room frames a poll is writing against their reply's bounds
- keep a room frame off a member's waiting poll under out-of-order broadcast
- a long-polling member's blocked poll write no longer stalls the room
- resume a room member's poll outside its mailbox lock
- keep room frames in per-member mailboxes, counted once and bounded per reply
- deliver a room reply whole to every long-polling member of the room
- deliver a stream-end frame a second filter defers again, instead of dropping it
- run @Ready once when a long-polling client re-polls over a suspended poll
- keep long-polling polls waiting on a run out of the streaming reattach slots
- read each frame of a multi-frame message when capturing the run id
- forget long-polling clients that stopped polling; run @Ready once for racing polls
- answer a long-polling run-id poll only with what its tracking id was not sent
- run @Ready once per long-polling client, not on every poll
- answer a long-polling reattach poll with its run's replay at once
- read request attributes from the Atmosphere request once the container recycled it
- a long-polling poll unregisters only itself, atomically, also on a failed write
- keep a long-polling client's next poll when a write fails on the poll it replaced
- keep a long-polling client's next poll subscribed when a write hits the returned one
- keep request attribute writes on the Atmosphere request once the container recycled it
- start a command answer's session before the command runs
- answer a slash command on the sender's connection over SSE and long-polling
- say no skill scope runs when an unknown scopeTier has no Guardrails
- track long-polling polls as live from before the suspend; a stale poll's loss keeps state
- let an identity-stamping AiInterceptor run before the endpoint's guardrails and policies
- send a scope breach's redirect message verbatim instead of having the model render it
- record a same-id reconnect as live as soon as it is suspended, not once set up
- stop tracking a WebSocket or SSE connection as live once its suspend times out
- warn when a closed host configuration leaves its generation knobs in the settings
- destroy the framework when the cost guardrail bridge or Vert.x setup fails
- keep the init failure reported when destroying the framework throws an Error
- throw an annotation processor's init failure from the no-argument init()
- report a judge that never judged as skipped, not as a passing score
- attribute a dispatch journaled before its coordination start to its coordinator
- warn when an explicit base URL sends an llm.mode=local run to a remote endpoint
- fall back to no-op metrics when micrometer is absent, as the other processors do
- admit the user's message against the scope before A2A and AG-UI run @Prompt
- mark a going-away close message before it reports the client's close
- warn when a skill scopeTier discards or narrows the class's restrictive @AgentScope
- report an invalid @AgentScope once per registration, not once per resolved path
- let the startup-team CEO admit questions about no-code and AI programming markets
- an explicit restrictive @AgentScope beats a scope derived from skill Guardrails
- release the open JAR and pending streams when a processor stops the annotation scan
- destroy the framework when its init or the AI runtime check fails at startup
- warn at startup when the LLM settings in use predate the configured generation knobs
- install the atmosphere.ai.* knobs before the application's own beans are created
- fail a plain servlet init when atmosphere.ai.runtime names no available runtime
- name atmosphere.ai.runtime, not missing JARs, when a fallbackStrategy has one runtime
- give a still-running host its AI knobs back when a later host configuration closes
- leave a tracking id's state to the connection that replaced a late-noticed lost one
- judge an injected proxy by when it was written into its field, not when it was created
- keep a lost connection's conversation when its client is back under the same tracking id
- run no reattach grace while a reattached client listens, restart it on each long-poll
- fall back to LLM_MODE/LLM_MODEL/LLM_BASE_URL and drop the stale runtime cache
- save the state of a poll replaced by one answered from the cache
- keep a stored injected resource on its own client and equal to its resource
- resolve injected resource, request and response fields per calling thread
- keep a polling client's session when its re-poll is answered from the cache
- console discovers the registered endpoint in the same order as Spring Boot 4
- startup-team fleet dispatches in-process so it works when Spring picks the port
- console info reports mode, path-template endpoints included
- explicit unrestricted @AgentScope overrides a scope derived from skill Guardrails
- label the stats footer in streamed chunks, not tokens
- let ms-governance-chat's legal-escalation policy answer legal language
- admit the user's message against the endpoint scope before @Prompt runs
- keep a resource whole until a @Disconnect another thread claimed has returned
- cancel delayed broadcast tasks on destroy and complete on-resume futures
- dispatch @Disconnect for an idle eviction under a close think time
- keep a container's own going-away WebSocket close cancelled
- report a dropped WebTransport session as abnormal, not closed by the client
- bind an injected event to its client outside the callback that injected it
- keep a server-initiated 1000/1001 WebSocket close cancelled
- classify a path-template console endpoint before any client connects
- cancel the futures of on-resume and delayed broadcasts a destroyed broadcaster drops
- release a broadcast future's whole count when its delivery reaches no resource
- close the WebSocket with 1000 on disconnect so the server reports the client leaving
- mark a model call cancelled when the cancel lands before its handle is published
- end a model call the admin cancel or idle sweep cuts short in a cancelled error
- send the prompting client a terminal error frame when an Error escapes @Prompt
- capture a run's replay frames below AiStreamingSession so streamed tokens replay
- name the local Built-in embedding model with LLM_EMBEDDING_MODEL
- end a run the disconnect cancelled in error and document what reattach replays
- end a reattached client's stream on every run terminal path, not only a captured complete
- run cache records the commit a branch ref resolved to and rebuilds when the branch moves
- single-jar fleets dispatch in-process so they work when Spring picks the port
- grpc-chat exec plugin reads exec.mainClass so -Dexec.mainClass starts the client
- useStreamingRN ends an in-flight turn and drops its open status when backgrounded
- write AgUiStreamingSession frames to the container response past the SSE interceptor
- prune connection and lock state, keep one session per polling client
- frame live SSE deliveries once whatever the Accept list, keep WebSocket JSON unframed
- write self-framed SSE events past the SSE interceptor for A2A and MCP
- end the run on an emitted Complete and stream AG-UI sessions through the pipeline
- make RUN_ERROR terminal on every path and close-once with the wrapped session
- emit AG-UI schema field names for tool, step, error, reasoning and snapshot events
- keep launcher state per sample and port so parallel lanes can boot one sample
- scrub the operator's messaging-channel credentials from booted samples
- expo client takes SafeAreaView from react-native-safe-area-context
- low-level raw ops feed refuses POST broadcasts from outside the on-call rota
- grpc-chat puts logback-core on its run classpath so the server logs again
- ship the Atmosphere favicon in the samples that run without a Boot starter
- embedded-jetty chat frames its handshake and heartbeats inside Jetty's idle timeout
- ai-classroom reads each resource's room instead of a shared @PathParam field
- team-rooms reads the Console envelope and replies with a message field
- document gemini-2.5-flash as the sample LLM_MODEL default
- print checkpoint list progress on stderr so its stdout is pure JSON
- checksum a cached Quarkus app tree and rebuild it when it is modified or missing
- suggest the closest sample names when run or info is given an unknown sample
- key the run cache on an explicit source ref and verify the ref a cached jar was built from
- refresh the dashboard tiles when its event socket opens
- show a refused journal or audit read as access denied, not as an empty list
- say metrics are not exposed instead of asking for traffic on health-only hosts
- keep the Chat tab mounted so leaving it keeps the conversation and subscription
- update the Interactions history row when the detail pane sees a new status
- serialize array and object tool arguments in the tool card preview
- send A2A v1.0.0 method names from the a2a transport and sample docs
- log retried transport failures at info and keep error for the terminal one
- make useStreamingRN suspend, close or keep the stream on AppState changes
- clear the streaming hooks' connection error when the transport opens or reopens
- make composed fleet agents reachable from the coordinator
- resolve the SMT checker once instead of per call
- activate a channel only when its credential is non-blank
- send snapshots, patches and custom values as JSON structures
- emit spec-valid SSE events for message/stream
- attribute a checkpoint approval to the approver agent
- warn when atmosphere.ai.runtime names a runtime that is not running
- read skill-file tool names with the grammar atmosphere import uses
- forward the rest of a run to a client that reattaches mid-stream
- extract long-term memory facts only under the identity recall reads
- count every endpoint's sessions in the atmosphere.ai.active_sessions gauge
- stop the embedding scope guardrail logging an ERROR on every local-mode turn
- classify a path-template console endpoint before any client connects
- keep one durable session per WebSocket across message frames
- resolve an injected AtmosphereResourceEvent per calling thread
- report a 1000/1001 WebSocket close as closed by the client
- complete a broadcast future when its resource leaves mid-delivery
- deliver the Koog coordinator's final answer and show its journal in admin
- give the ADK tests a Gemini key so the per-request runner test runs without a host key
- check the gate self-test paths of push and pull_request apart
- say which reads stay on the static API, what is deprecated, why Quarkus binds JVM-wide
- deprecate AiConfig.installHostConfig in favour of the host's own AiEnvironment
- run the gate self-test when a file one of its cases injects into changes
- say which static AI reads framework code still makes and why each is allowed
- allow Spring's @Primary in the doc-symbol gate, as the starter README cites it
- make AI state belong to the application that owns the request a blocking invariant
- also flag the no-argument EmbeddingRuntimeResolver and DecisionModelResolver reads
- fail the build when framework code reads AI state through the process-wide statics
- read a hand-built client's, a workspace's and Quarkus's AI state via AiEnvironment
- pin how the adapter auto-configurations hand their clients to the context's application
- pin that a runtime instance belongs to the application that resolved it
- say which AI state is per application and what still reads the static API
- let the settings and workspace-ownership test hooks reset every open AI environment
- pin that a closing application hands the process default's settings to a survivor
- close the AI environment the extension creates on a failed start and on destroy
- resolve AI settings, knobs and runtimes through an AiEnvironment model
- wait for every frame of the out-of-order room test, not just both terminals
- say a reply past the 64 a room member follows is kept once one of them ends
- say how replay frames number per transport and when a waiting run-id poll returns
- say which long-polling clients run @Ready more than once
- answer every slash command over the Console's long-polling fallback
- pin that an invalid @AgentScope's own topics join an explicit skill scopeTier policy
- let the reattach-timeout test's prompt timeout fire after the reattach on a loaded machine
- say which hooks a redirected or denied turn skips for a before-admission interceptor
- send the durable-chat readiness message once instead of every 500ms
- wait for broadcast delivery in the session-token-expiry spec too
- wait until a durable-sessions chat socket receives broadcasts before using it
- a same-id reconnect's own answer streams on past the late loss, on WebSocket and SSE
- wait for the browser-agent boot lines instead of reading the log once
- name the transports whose page reload gets the reattach grace
- send the close message as a query string, the shape the pagehide beacon has
- read the close reason of a beacon whose parameters ride in the query string
- drive the going-away close message over a real SSE, long-polling and streaming connection
- pin the startup-team CEO admission scope to its @AgentScope
- keep the failing-processor test out of the packages other framework tests scan
- prove the poll a cached answer replaced saves the state itself
- describe the reattach grace for a late-noticed loss, long-polling and a same-id reconnect
- wait for the reattached client's terminal frame, not only its released subscription
- pin that a bean resolving the runtime at creation gets the named one
- name the filesystem routes key AgentFileSystemProvider actually reads
- a poll resumed by a broadcast is not saved when the next one takes over
- pin the derived scope purpose for a skill reference on @Coordinator
- annotation Javadoc states the unrestricted-override scope precedence
- registering an unrestricted @Agent or @Coordinator over skill Guardrails logs one WARN
- ignore JDK class-loading pins in the probe pinning test
- boot the channel samples with placeholder tokens and assert the channels actually running
- give the repoll recency test a window a loaded build cannot overrun
- drop the stale capture position from unwrap and note the admin cancel's error frame
- say what a run-id reconnect replays, apart from the UUID broadcaster cache
- pin the anonymous memory owner through a real prompt dispatch
- match matrix rows 11, 13, 16 and 25 to the samples they drive
- drive the Expo client's input with Maestro on Xcode 27, keep idb for reads
- move the expo client to Expo SDK 57 so current Expo Go opens it
- ms-governance README quotes the shipped policy file and live admin answers
- pin one @Disconnect for a client reconnected to a restarted server
- read the JFR pinnedReason as Object, not char[]
- log the gRPC client-transport claim on async-io.live
- expose the server tracking id as Subscription.uuid (#2787)
- tag error events with willRetry and attempt (#2790)
- honor RetryStrategy with a single reconnect-delay calculator (#2788)
- dispatch @Disconnect once per resource when a broadcast races the close
- report unknown run samples and key the jar cache on the override version
- pin import's Spring Boot parent to the reactor pom and ship mvnw
- make the composed coordinator jar runnable and discoverable
- destroy the framework after the admin lifecycle stops, not before
- decode CONNECT-stream capsules instead of dispatching them as messages
- stop a broadcast reaching a closing resource from re-running @Disconnect
- bump Spring Boot to 4.1.1 for Spring Framework 7.0.9 across the Boot 4 line
- pin lz4-java to 1.11.4 for the yawkat LZ4 advisories
- stop release preflight flagging the atmosphere.js docs URL as a stale asset path
- keep query values decoding to control characters raw; WebTransport spells spaces %20
- percent-decode query parameters mapped to request headers
- guard the IIFE window globals with a tsup footer. Fixes #2791
- send request headers as real headers on same-origin fetch (#2789)
- open long-polling after subscribe() resolves and the handshake (#2784)
- send the close message on close() and pagehide (#2783)
- make react-markdown and remark-gfm optional peer deps (#2786)
- derive VERSION from package.json at build time (#2785)
- make an explicit WebSocket/WebTransport close terminal (#2782)
- parse the handshake only when one is expected (#2781)
- label the issues a release fixed with its version
- assert the raw control-character values directly; note Boot 4.1.1 manages pgjdbc 42.7.13
- bump vue to 3.5.44 in atmosphere.js and Console for npm advisories
- bump jsoup to 1.23.2 and align spring-ai-alibaba to Spring 7.0.9
- derive Atmosphere versions in release scripts and gate hardcoded literals
- cite the moved ACS extends resolver and fixtures, and name the drift source
- diff ACS fixtures against responsibleai/agent-control-spec
- getHeader returns decoded query-parameter values
- publish the legacy atmosphere.js 4.x npm package from release-4x via Trusted Publishing
- add workflow publishing the legacy atmosphere.js 4.x client to npm
- reconnect is off unless the request sets it
- cover an empty first long-polling body under the protocol (#2784)
- bump Google ADK to 1.11.0 and LangChain4j to 1.21.0
- stop publishing the legacy assembly distribution to Maven Central
- add a bounded, strictly decoded request body read to IOUtils
- add atmosphere-ai-decision-typesafe, a DecisionModel over the TypeSafe System One API
- route each request to a handler, the LLM or a person before dispatch
- signal injected governance guidance and assert CARRY on it in the e2e
- add the DecisionModel SPI and route the LLM injection tier through it
- score the decision field's value distribution, not the fluency of every token
- route completed turns on confidence (ACT/CONFIRM/ESCALATE, unknown fails closed)
- add carnet issue claims, the bilan completion score and remote-first vault sync
- RoomProtocolInterceptor reads at most maxBytes+1 of a POST body looking for a room command
- route slash commands and @Message inputs from SSE and long-polling POSTs
- HeartbeatInterceptor peeks at most padding+1 bytes instead of reading every POST whole
- render raw HTML in chat text literally so and List are not dropped
- bound prompt POST bodies; answer 413 when oversize and 400 when malformed
- deliver a whole AI reply to the next long-poll instead of its first frame
- complete a long-poll resumed before its suspension took effect
- pin checkpoint-temporal's Jackson 2 to the root jackson2.version (2.22.3)
- dispatch an agent handoff as a prompt of the same connection
- close the Sept-Oct Jackson + npm advisory batch, one property for the Boot Jackson line
- run a prompt only on a connection of its sender's identity
- keep a run reattach replay off the cluster filters
- keep cache replays off the cluster and send room messages to other nodes again
- wait for the next poll when a prompt's connection was resumed or recycled
- give a DSL agent the protocol handshake recorder
- run a prompt only on a connection its own endpoint suspended
- keep a broadcast to chosen resources off the cluster filters
- subscribe the classroom Expo client with the Atmosphere protocol on
- dispatch a prompt to its connection directly, never through the path's filters
- keep half the repoll waiter slots from handshake-only ids, forget closed ids
- run @Prompt only for a prompt dispatched to the receiving connection
- wait on a handshake-assigned tracking id only within the repoll wait
- name a session in the WebSocket refusal frame so subscribeStreaming reports it
- never send a deferred stream end to every subscriber after a disconnect
- read a deferred stream end's recipient while its terminal frame is filtered
- send a filter's deferred stream-end frame to the sender, never to the whole path
- answer a WebSocket prompt whose connection is gone with an error frame over its socket
- keep a client-chosen tracking id across reconnects
- new client tracking id per HTTP subscription, resend under the current one
- answer a malformed prompt tracking id 400, let a prompt wait on a long-polling handshake id
- open protocol long-polling after its handshake; hooks keep state on send errors
- name HTTP subscriptions without the protocol; Console frees a refused prompt
- bound waiting prompts across every @AiEndpoint, refuse them at once on destroy
- never fan a prompt out to every subscriber of an @AiEndpoint path
- resend an HTTP push the server answers 503, report one it refuses
- score every embeddable forbidden topic before the semantic-intent tier degrades
- check the embedding scope threshold before an unembeddable topic degrades a request
- check the semantic-intent floor before forbidden topics, report its resolved impl
- degrade the semantic-intent scope tier to rule-based instead of admitting all
- time out TypeSafe connects cut short by the deadline, document what its probe checks
- keep TypeSafe answers when token counts are unreported, record no verdict on interrupt
- abort TypeSafe requests on close, retry connect timeouts, log config once
- bound TypeSafe retry waits, share its probe verdict, enforce required fields
- close the resolver's cached decision model on reset and recheck a provisional fallback
- close decision-model registrations the resolver loads but does not select
- keep intent-routed turns out of model metrics and bound confirmation waits
- end endpoint intent confirmations before the prompt watchdog; signal routes on OpenAI
- skip RAG and cancelled turns in intent routing and escalate unconfirmable CONFIRM at once
- read the prompt from the request entity on long-polling and SSE POSTs
- announce presence/leave when a room member's connection drops
- keep governance guidance frames off room replies and report only what reached the model
- read the LLM scope fail-open property on each uncertain verdict
- gate moderation only on undecided blocked categories and size the shared decision pool
- fail the LLM moderation detector closed through the DecisionModel
- fail the LLM scope classifier closed through the DecisionModel
- score the decision value the reply carries and never clear a flagged document
- gate model-reported injection verdicts like measured ones and bound decision replies
- score the decision value the model emitted and keep decision turns on chat completions
- score decision rivals before the value and resolve unseen mass against the answer
- write broadcast frames in the passivation, budget-breaker and structured-output handlers
- wait for the long-polling receiver itself before broadcasting in WAsync test
- assert the AG-UI Console keeps its input enabled while streaming
- honour quarkus.atmosphere.websocket-support in both container modes
- ignore JDK class-initialization pins in the TypeSafe probe pinning test
- state where prompts and replies go now that plain broadcasts are never prompts
- give the repoll gate's expiry test a window a loaded machine cannot outrun
- pin streaming's new id on reconnect and the 1 s retry without Retry-After
- pin repollWaitMs=0 refusing a between-poll prompt at once
- state that a client-chosen tracking id bypasses the UUIDProvider and first-request marks
- state that long-polling routes an @AiEndpoint prompt but does not carry its reply
- pin which refused send marks a prompt undelivered
- pin the getRandomValues tracking id on a runtime without randomUUID
- pin the repoll gate giving its shared waiter slot back and the documented init-params
- pin the handshake recorder on the Spring Boot default AI endpoint and @Coordinator mappings
- pin repoll-gate id expiry, the full-set sweep and the 30 s wait cap
- pin AtmosphereChatTransport handing the send error to onError intact
- pin the documented 3-attempt and 5 s send-retry bounds as literals
- name atmosphere-3.x the bug-fix-only legacy branch and never touch 2.x
- state the duplicate-import limits, Spotless coverage gate and pre-push modes
- run the root-project Spotless check in pre-push validation
- fail validation on a Java file outside every Spotless include
- match duplicate imports on the imported name, not the raw line
- log the overstated Spotless header coverage
- restore the code rationale that lived in removed NOPMD comments
- catch duplicate imports that differ only by trailing blanks
- header-check every staged Java file's owning module at commit
- run the Spotless gate on the three samples that skipped it
- remove PMD and its ruleset, skip flags and NOPMD comments
- enforce the Java license header with Spotless instead of the hook
- normalize the license header of 26 Java files to one form
- replace Checkstyle with a Spotless import and tab gate
- reset keeps built injection screens; true+no confidence flags
- remove a merge-conflict marker left in AtmosphereFilterChain Javadoc
- say the quarkus long-polling test runs only in the quarantine lane
- point the quarkus long-polling quarantine at the delivery design issue
- say the coverage gate skips docs-only pushes and log the gate's CI claims
- list the coverage gate's suite under CI=true and pin that the gate fails closed
- anchor the ai-classroom testMatch and fail a spec two workflow projects run
- pin the identity a re-joined room member's drop announces
- count statically skipped specs as uncovered by the spec-coverage gate
- force the WebTransport fallback and require an answer over WebSocket
- prove the missed history message reached the server before the sinceId re-join
- require the drained classroom question to get the code room's answer, not an error
- say the five resilience projects drive the bundled Console, not the removed React app
- take spec coverage from playwright --list under the per-push env, grep included
- drive the quarkus long-polling test through the Console, keyless
- run the five orphaned resilience specs and fail when a spec file matches no running project
- anchor every Console connect guard so 'Disconnected' no longer satisfies it
- scope the governance Decisions-tab PREFER row to this run's conversation_id
- wait for a real Connected pill before sending in the governance-feedback spec
- document fail-closed LLM scope and moderation tiers and log the drift
- run the nine unmapped Playwright projects and fail when a project runs in no workflow
- gate JMH regressions on a same-runner A/B instead of stored scores
- give npm five minutes to serve a published create-atmosphere-app
- make the WebTransport offline-queue drain test deterministic
- point the README at the Quarkus Vert.x container mode
- serve Atmosphere from a Vert.x route with quarkus.atmosphere.container=vertx
- add completions, resource templates, tool annotations and outputSchema
- advertise MCP Apps under the spec id io.modelcontextprotocol/ui
- block the drift-log stop hook at most once per session
- register the commons-pool2 pool providers only when commons-pool2 is reached
- scope the drift-log stop hook to changes made during the session
- bound parallel fan-out with a fleet-wide maxParallel permit pool
- bump Bouncy Castle to 1.86 for CVE-2026-8763 and CVE-2026-13506
- close Tomcat auth-bypass CVEs and the vitest mocker path traversal
- boot fixture servers from packaged artifacts instead of Maven goals
- make the Expo client server URL an env override, not a source edit
- make the queued-past-timeout maxParallel test deterministic
- pin the router behaviours a Vert.x container mode relies on
- prove BlockingIOCometSupport suspends on virtual threads; drop stale JDK 25 notes
- log unverified claims in the Vert.x-mode design session
- extract framework bootstrap helpers from the servlet
- build Quarkus native with the Mandrel JDK 25 builder image
- bump Quarkus to 3.39.5
- run the official MCP conformance suite on both dialects
- drop the org.json Dependabot ignore and the inert dependency-graph config
- keep the personal-assistant transport open while keying memory on the token
- stop compose hanging without a TTY and warn on an inherited LLM_BASE_URL
- resolve the run owner from the AuthInterceptor principal
- key personal-assistant memory on the authenticated principal
- track Boot 3.5.15's Tomcat 10.1.55 in the spring-boot3 profile pin
- close 72 of the 74 open Dependabot alerts across nine packages
- pin the parity trail in save order, not as a sorted multiset
- log the blog-audit drift entries
- cite the shipping rate limits in the OWASP A09 evidence
- move to Jetty 12.1.12 and port HTTP/3 to the relocated QUIC API
- type-check the Console on TypeScript 7 and make .d.cts reachable
- move atmosphere.js and the e2e suite to TypeScript 7
- take the sample-frontend group bumps, holding TypeScript at 6
- cite Quarkus 3.36.3's real netty baseline in the five BOM pins
- add the classic-rooms template and gate the two template maps in lockstep
- add spring-boot-low-level-handlers, the layer under @ManagedService
- add spring-boot-team-rooms, a classic-annotation multi-room chat
- stop the personal assistant overwriting an upstream-resolved ai.userId
- skip cross-session recall when the resolved runtime is the demo fallback
- reattach two Javadoc comments orphaned by the owner-reclaim insert
- stop the CHANGELOG generator crediting reverted commits
- keep the run owner across a recycled request so fact extraction still runs
- make the classic-annotation samples work at runtime, not just in tests
- resolve templated endpoint paths on WebTransport, not just requestURI
- fail a fixture boot as soon as the process dies, not after the timeout
- fail the coverage map on entries for samples that no longer exist
- resolve e2e coverage entries to real specs, projects and CI legs
- resolve @PathParam on @RoomService and add it to the servlet scan
- require evidence in the four matrix rows that certified without it
- log the offline-maven CI regression and the CDI annotation false positive
- register the two classic-annotation samples across every gate and doc
- log the fabricated container-ledger blog claim and the relayed RAG negative grep
- forbid host-network toggles, record the NetInfo assertion as PARTIAL
- scope workspace RUNTIME.md settings to their agent via AiConfig.configureForAgent First workspace seeds the process default, later ones stay agent-scoped; the built-in runtime serves scoped agents from their own client (registre#39)
- ship the voice-mode endpoint driving the speech-to-speech loop VoiceEndpointHandler resolves RealtimeVoiceProvider per connect; mounted behind atmosphere.ai.voice.enabled on Spring and Quarkus (registre#25)
- per-user MCP credentials via McpTrustProvider, facade on the selection path connectForUser sends the resolved Bearer credential and fails closed unauthorized; ToolSelection composes ToolExtensibilityPoint per request (registre#24)
- arm durable approval-expiry timers for journaled approvals DurableApprovalExpiry is DurableTimerService's production consumer, wired by both durable-run installers; markFailed never demotes COMMITTED (registre#26)
- implement expose, snapshot and hibernate on both shipped backends Docker uses pause/commit/port-publishing recreation, in-process copies its workdir (registre#5); README stops naming non-existent backend modules
- execute saved workflow manifests through AgentFleet with run/approval endpoints WorkflowRunner dispatches agent/condition/fan-out/join/approval/output nodes (registre#1); Quarkus gains the workflow surface and live coordinator wiring
- read WEBTRANSPORT_PROTOCOL knob to install custom WebTransport protocols Custom protocol owns message/lifecycle callbacks (registre#28); tool/voice SPI docs made truthful (registre#24, registre#25); exec-maven-plugin version pinned
- expose fleet health, make VerifyCli launchable, honest fan-out contract GET /coordinators/{name}/health reads AgentFleet.health(); exec mainClass pinned for the verifier CLI; FanOutStreamingSession documented app-constructed (registre#43)
- surface priced call cost as business.session.cost response metadata CostAccountant gains priceUsd; the accounting session emits the real figure and BusinessMetadata docs now state who writes what (registre#42)
- emit MESSAGES_SNAPSHOT at run start and document the produced event set 23 of 27 AG-UI types now have producers; the chunked/raw alternates are documented parse-only by design (registre#29)
- stream reasoning and citations as first-class AiEvents Anthropic thinking blocks and Cohere citations now produce ReasoningDelta/ReasoningComplete/Citation, mapped to AG-UI's REASONING_* and CUSTOM (registre#16)
- wire the agent-state control plane to both admin transports StateController serves the live per-agent AgentState registry with guarded mutations; the vacuous [200,404] e2e now discriminates (registre#21)
- register live protocol bridges and list them on the admin plane Processors install Mcp/A2a/AgUi/InMemory bridges via ProtocolBridgeRegistry.install; GET /api/admin/protocols reports runtime truth and the false SPI comments are corrected (registre#22)
- render the coordination causal tree from the journaled lineage GET /journal/{id}/tree reads CoordinationProjection on both admin transports, giving the envelope lineage its production consumer (registre#23)
- route shared-channel free text by address, default agent, or sole binding @name/name: addressing beats registration order; atmosphere.channels.default-agent catches the rest; ambiguity now warns (registre#34)
- run --env sets real child environment variables that beat ambient exports -D-only mapping let an inherited LLM_BASE_URL silently redirect a local run to a remote provider; e2e regression added, sweep matrix model guidance corrected
- voice config strings are Optional, SmallRye rejects empty-string defaults
- propagate response metadata to the task and retire the mispointed marker sendMetadata lands on TaskContext (Task/TaskStatusUpdateEvent carry it); DurableTimerService docs now register the unwired-consumer limitation (registre#26)
- surface encoder/decoder registration conflicts and decode failures Last-wins codec conflicts and the first throwing Decoder now WARN instead of passing silently at trace (registre#40)
- warn once when durable run state degrades to in-memory The first RunJournal failure is an operator-visible WARN instead of TRACE; repeats stay quiet off the hot path (registre#32)
- journal denied dispatches by wrapping governance inside journaling journal(intercepting(base)) is now the default composition, upholding Decision.Deny's documented audit guarantee (registre#8)
- count tool-call payloads, honor maxMessages and reserve headroom in TokenWindowStrategy Tool arguments now consume the token estimate, maxMessages caps the selection, and forModel budgets 75 percent of the window (registre#33)
- warn loudly when a second workspace clobbers the process-wide AiConfig RUNTIME.md application stays last-write-wins but now registers the limitation and names both workspaces on the WARN (registre#39)
- honor the configured session TTL in the Redis store removeExpired(ttl) now expires on lastSeen against the passed ttl like the sibling stores, instead of discarding it (registre#11)
- protect each coordination's resume anchor from global eviction Oldest non-anchor snapshots evict first in all three stores; anchors go only when the cap is below the live-coordination count, with a WARN (registre#36)
- honor configured pool bounds in virtual-thread mode An explicit maxProcessingThreads/maxAsyncWriteThreads now bounds a virtual-thread pool instead of being silently ignored (registre#7)
- signal structured-output parse failure via metadata breadcrumb An AiEvent.Error hard-failed minimal sessions through the default emit mapping; ai.structured.parse_failed keeps terminal semantics (registre#30)
- frame binary payloads instead of corrupting them as text Binary rides a 0x00 length-prefixed frame on server and JS client; text keeps newline framing; console bundles re-synced (registre#15)
- thread client history to the OpenAI-compatible endpoint without memory Prior turns and client system messages ride REQUEST_HISTORY_METADATA_KEY so standard SDK clients no longer lose their context (registre#6)
- surface structured-output parse failures as a recoverable Error event A parse failure on complete() was swallowed at DEBUG, leaving a clean terminal frame indistinguishable from an empty answer (registre#30)
- drop tool string arguments truncated mid-value instead of delivering them An unterminated string in cut-off model JSON now fails required-arg validation rather than silently shortening the value (registre#37)
- deliver content and metadata on the live AG-UI session sendContent now uses the default text/breadcrumb routing and sendMetadata rides the CUSTOM event instead of vanishing (registre#13)
- honor the fluent contract on DefaultBroadcasterCache listener registration Returning null NPE'd the BroadcasterConfig loop; registration now warns that the no-op cache fires no events (registre#14)
- implement WebSocket ping/pong and close(code, reason) JSR356 binding transmits control frames and coded closes; the base close(code, reason) now closes instead of silently no-oping (registre#10)
- decode the stream transport incrementally to keep split UTF-8 intact Per-chunk new String() corrupted multi-byte characters at buffer boundaries (registre#38)
- stop registering webhook routes for Gateway-only channels DiscordChannel returns a null webhookPath (no unauthenticated dead route) and its webhook SPI methods fail closed (registre#44)
- enforce the documented same-origin policy on WebSocket handshakes WEBSOCKET_REQUIRE_SAME_ORIGIN is now read (default true); cross-origin browser handshakes are refused unless explicitly disabled (registre#18)
- enforce the isolation-tier floor on the production resolve path @SandboxTool gains minTier; named backends below the floor are refused and empty backend selects by tier via Sandboxes (registre#20)
- tighten and verify seal key permissions for pre-existing key files loadKey now restores owner-only permissions and fails loud when the key stays accessible beyond its owner (registre#17)
- verify A2A agent-card signatures on the consuming side isAvailable now enforces self-integrity on signed cards and supports a pinned peer key that fails closed (registre#19)
- carry caller identity into POST_RESPONSE policy evaluation inspectResponse gains an identity-aware overload wired through DispatchDecorators, so output authorization keeps its subject (registre#9)
- honor user/agent scoping in agent-state rules and workspace root getRules reads users/{userId}/USER.md and agents/{agentId} overrides; workspaceRoot returns the per-agent subtree (registre#12)
- apply PolicyDecision.Transform to the dispatched fleet args Transform now re-evaluates per String arg so redaction lands on the real payload; unapplied transforms report Proceed, not a false rewrite (registre#4)
- fail closed when the run owner principal cannot be resolved A thrown getUserPrincipal now registers the run as unresolved-principal, refusing reattach instead of granting the anonymous carve-out (registre#3)
- publish create-atmosphere-app on every release and fail loudly It was gated on atmosphere.js changes and swallowed publish errors, so npm sat on 4.0.65 through two releases.
- reattach the durable-run spine javadoc
- model the crash window without demoting committed effects markFailed refuses COMMITTED->FAILED since the expiry-race guard; the durability tests rebuild the resumed journal from the surviving effects instead
- reattach the workflow bean javadoc
- delete 13 never-read ApplicationConfig constants Dead knobs promised behavior nothing implements (registre#18 sweep); WEBTRANSPORT_PROTOCOL is now read and PROPERTY_SERVLET_MAPPING has a live reader, both stay
- bind JSON-RPC parameters through the shared ParameterBinder protocol-common's binder replaces the hand-rolled copy; MCP contributes only its injectable predicate and resolver (registre#27)
- browse the server origin in grpc-browser instead of about:blank about:blank hands WebSocket a literal null Origin, which the default-on same-origin handshake check rightly refuses (registre#18)
- pin the per-agent workspaceRoot contract in StateControllerTest Follows the agent-state scoping fix (registre#12)
- correct five stale javadocs, register the metadata drop
- run the limitation gates in CI and review phases weekly
- enforce the limitation gates in pre-push validation
- adopt limitation register, fix two stale javadocs
- prepare next development version 5.0.43
- prepare for next development iteration 4.0.68-SNAPSHOT
- make the vector store opt-in so keyless retrieval keeps its provider An empty store becomes the retrieval source and starves the demo path — the rag-chat-commands e2e caught it.
- scrub SPRING_AI_* and read warnings from binary sample logs Relaxed binding let an ambient SPRING_AI_OPENAI_BASE_URL redirect samples off the keyless-local backend.
- reject flag-shaped project names and unknown checkpoint options
atmosphere new --list-templatesscaffolded a directory named after the flag; checkpoint silently ignored --url. - build the vector store so retrieval is actually grounded Un-exclude OpenAiEmbeddingAutoConfiguration and gate the bean on a property, not @ConditionalOnBean.
- treat unreachable container daemon as engine unavailable
- allowlist ConditionalOnBean/ConditionalOnProperty doc symbols Sibling Spring conditions were already listed; these two were missing.
- document the transport headers replay requires A bare curl returns 200 with an empty body because reattach only runs for WS/SSE/long-polling.
- unwire mcp-client spec until its build moves out of the hook
- stop dependabot rewriting the maven wrapper
- hold the Maven wrapper on 3.x in dependabot
- bump Embabel to 1.5.0 and MCP Java SDK to 2.0.0
- bump Spring Boot 4.0.7 to 4.1.0
- bump org.jetbrains.kotlinx:kotlinx-serialization-core-jvm (#2748)
- bump every version-bearing file in one commit
- prepare next development version 5.0.42
- bump version to 4.0.66
- prepare for next development iteration 4.0.67-SNAPSHOT
- add opt-in durable batch job API at /atmosphere/v1/batches riding AiPipeline SQLite-backed submit/poll/results/cancel, default off; eval dataset runner is the first consumer
- opt-in Ed25519 state sealing wires AgentStateIntegrity into FileSystemAgentState
- give the classroom a @RoomService chat channel with history A templated @RoomService path created one shared room for every path value, so two classrooms saw each other's members and history
- report a non-runnable sample before checking the JDK
- scaffold from the ref that matches the pinned version, and make compose work anywhere
- stop provider defaults from shadowing a local backend
- boot the reactor version, never the newest jar lying in target/
- never drop a React Native send, and ship the types we advertise
- send tool-call arguments as a JSON object on the OpenAI wire
- screen tool-call arguments in deny lists and reach local Koog backends
- treat a local backend as reachable without a credential
- report the ms-governance rule count from the loaded policies
- render every streamed chunk and scope tool cards to their turn
- build a default model for keyless local backends
- boot exec-type samples through the helper instead of by hand grpc-chat is the matrix's only exec sample and the helper died on it, so it had to be started manually with the LLM env scrubbed by hand
- use the Session-bearing SendResult constructors WebSocket 2.2 deprecates the no-Session forms and the build is -Werror.
- register @Message payload types in the Quarkus deployment processor The Spring AOT half landed separately on main; this is the Jandex-side equivalent, so the Quarkus native lane stops dying on the payload
- stop the demo runtime shadowing a locally served model A local backend needs no key, so a blank key was the wrong test for "no backend" — LLM_MODE=local reached Ollama and still answered from the canned script
- restore the request body after reading it for a room command Draining the stream without writing it back meant a @Message sent over long-polling or SSE never reached the annotated method
- register the payload types an annotated method carries Encoders were registered but not the DTO they convert, so a native image invoked the codec and then failed on the payload
- register RoomServiceProcessor so @RoomService works under GraalVM It was the one @AtmosphereAnnotation processor missing from the registry; the guarding test only checked the list was non-empty, so it never bit
- scrub ambient LLM env in the launcher; raise boot timeout to 300s Inherited LLM_BASE_URL sent local-mode samples to Gemini; also logs the 2026-08-07 drift.
- stage cli/samples.json with the docs it is validated against Every release landed one commit where the docs named the new version and the guard's source of truth still named the old one, turning CI red
- pin JDK 21 in the CLI unit job to match the CLI's own baseline
- log the false-green prime and the premature stops Two 2026-08-08 slips: -Pfastinstall disarmed -Werror; halting on actionable work.
- stop asserting which sweeper evicts the expired session Two sweepers race at a 1ms TTL; assert the eviction outcome, not the count.
- state the personal-assistant workspace's real persistence scope
- websocket-api 2.2.0 + client-api, kotlinx 1.11.0, setup-python v7 The API split at 2.1.0; client types need the companion artifact. Lands #2750/#2748/#2751.
- exclude unpatchable fastjson 1.x from the Alibaba framework GHSA-crf3-v9rr-v7hj critical RCE; 1.2.83 is the last 1.x and no fix exists.
- make three tests hermetic against machine state Pin fake LLM mode, drain to quiescence after join, retry the Docker probe.
- micrometer 1.16.6, pin jsoup 1.23.1 Closes GHSA-g3pr-3p32-fp23 + GHSA-w737-wx49-qj23 (server DoS) and GHSA-pmhh-3w7g-xqp8.
- drive WebSocket, SSE and the room protocol against the native binaries A JDK-only probe proves fan-out, @Message codecs and rooms; READMEs drop the now-false unproven lists
- drop hard counts that drift, and scope the gRPC native section The counts went stale within hours of being written; gRPC is registered but built natively by no lane
- re-add the AI dispatch job now that discovery survives native image The blocker that forced its removal is fixed; whether @AiEndpoint works natively stays unproven until this job is green
- correct LLM_MODE=local endpoint claim after shakedown run Runtime resolves mode=local to Gemini on the Spring path; add jstack + boot-hang triage.
- add release-sample-sweep skill and contributor doc Covers 31 samples, the Expo client and the atmosphere CLI as pre-release gates.
- prepare next development version 5.0.41
- bump version to 4.0.65
- prepare for next development iteration 4.0.66-SNAPSHOT
- index annotated classes at compile time via an annotation processor Auto-discovered by javac from atmosphere-runtime, so discovery works in any build without Spring AOT or Quarkus augmentation
- ship GraalVM metadata inside atmosphere-runtime Generated from the SPI and read automatically, so a deployment with no Spring starter or Quarkus extension needs no configuration
- let each module declare its own native-image metadata via SPI Replaces one list transcribed into three integration modules; atmosphere-ai/-mcp/-agent load classes by name and had no way to contribute
- resolve Atmosphere annotations at build time for native image Classpath scanning finds nothing in a native image, so the scan now runs during AOT and the runtime reads the recorded list
- register broadcaster caches so annotated endpoints can be created Loaded by name, so a native image could not build any Broadcaster; the failure was logged and swallowed, silently unregistering every @ManagedService
- stop the console-bundle gate firing on the release version bump Masks the package's own version from the fingerprint; it cannot change the emitted bundle but blocked the first commit after every release
- describe what the native lanes assert, and what they do not The previous text documented a limitation that these fixes removed; it now states the verified path and enumerates the unverified ones
- drive a real connection and assert the annotated @Ready ran Handler registration is silent, so behaviour is the only honest signal; validated against a JVM run first
- assert the annotated handler is installed, not just that a port answers Both native smoke tests curled a liveness URL that responds whether or not Atmosphere registered anything
- prepare next development version 5.0.40
- bump version to 4.0.64
- prepare for next development iteration 4.0.65-SNAPSHOT
- bound the default gateway and make checkpoint encryption readable safeDefault replaces a 1M/hour non-limiter with an anonymous bucket sized above the per-principal one; CheckpointStore.encryptsAtRest reports posture instead of only logging it
- bind tool-loop caps on AgentScope and CrewAI, discover TokenPricing AgentScope maxIters per request, CrewAI max_iter across the sidecar wire; ToolLoopGuard survey now names why SK/SpringAI/Alibaba cannot be capped
- beforeCompletion interceptor hook fires before the terminal frame Metadata emitted from postProcess was silently dropped at the closed leaf; the hook runs LIFO pre-terminal with Throwable isolation, consume-once arming, error-path invalidation and a reentrancy latch
- screen tool output for injection by default, marking not deleting Tri-state OFF/ANNOTATE/SANITIZE defaulting to ANNOTATE; bounded 256KB scan; init-param bridge; OWASP A04 now COVERED
- add LiteLLM proxy quick factory to OpenAiCompatibleClient
- resolve ACS manifest extends chains with upstream additive-merge semantics Depth-first chain resolution with canonical trust-root confinement, atomic policy bindings, cycle/depth/conflict errors mirroring Microsoft's resolver; URL extends rejected fail-closed and bundle refs rebased per declaring file
- relay HITL approvals across nodes so any node can answer Publishes an unresolved approval on a cluster broadcaster channel; the owning node completes the parked future, non-owners no-op on UNKNOWN_ID
- response-cache parity on @AiEndpoint, CrewAI schema facets, ADK step cap Consumers: AiStreamingSession gate + ResponseCacheConfig install at AiEndpointProcessor; ToolBridgeUtils schema on the CrewAI sidecar wire; LlmAgent.maxSteps opt-in
- parse and enforce MS Agent Control Specification manifests YamlPolicyParser routes the ACS root key to intervention-point bindings with fail-closed opa-backed rego verdicts; weekly conformance diffs upstream's own contract fixtures on main, retiring the pre-ACS pin
- carry enum, array and nested facets into Koog and Embabel schemas Both bridges flattened every structural facet to a string; Koog gains Enum/List/Object types, Embabel its enum/properties/itemType slots
- Tier-3 polish — observability, TCK depth, invariants, security defaults, DX Consumers: percentile+cached-token meters and console tab on both runtimes; behavioural CANCELLATION TCK + capability meta-gate across 12 runtimes; session-map sweeper and MCP teardown; Anthropic cache_control/tool-deltas/model enumeration; JDBC schema versioning; A2A raw-handler admission; webhook dedup; Kotlin agent DSL; markdown/sentence chunkers; 20 e2e tests returned to live coverage
- tool-call correctness — schemas, arg parsing, execution bound, MCP fail-closed Consumers: McpProtocolHandler tools/call gate; parseJsonArgs at 6 bridges; ToolExecutionHelper seam on all 11 runtimes; schema emitters for Built-in/Anthropic/Cohere/SpringAI/Alibaba; MetricsCapturingSession + admin snapshot
- error taxonomy, reranker, OpenAI serving, prompt registry, eval runner, cost parity Consumers: classifier at 12 runtime error seams + typed outer retry; over-fetch rerank on the retrieval path; /atmosphere/v1 via AiPipeline (default off); prompt: resolution at 3 processor seams; POST /api/admin/evals/run + CI smoke; Quarkus CostAccountantHolder install + servlet guardrail bridge
- opt-in tape redaction hook and checkpoint encryption at rest TapeRedactor SPI + PII redactor on both tape write paths; AES-256-GCM CheckpointCipher with legacy-plaintext migration; plaintext startup WARN
- wire GenerationParams into ADK, Semantic Kernel, Cohere, Koog adapters Contract test now forces every runtime to declare honor-vs-cede; README honoring matrix updated
- feed cost and tool-call meters at the shared metrics seam TokenPricingHolder gates dollars (no fabricated $0); starters install pricing; admin snapshot exposes costUsdTotal + tool timer
- record HITL approval decisions in the durable effect journal Crash-resume replays a committed approve/deny without re-prompting; timeouts and cross-principal re-drives re-prompt
- add SQLite durable-timer and run-journal backends
- add CheckpointStore producer and console parity
- add web-search tool and pluggable WebSearchEngine SPI
- add model context-window catalog for model-aware compaction
- add evaluator-driven refineUntil supervisor loop
- register managed-service interceptors and bind the prompt method by name Reflective instantiation failures were caught and logged, so the AI endpoint silently never registered under GraalVM
- declare the concrete store type on the lifecycle @Bean Spring AOT hinted CheckpointStore.start() while the container invoked it on InMemoryCheckpointStore, failing native startup
- runtime-init the two OpenSsl private-key-method interfaces too Their constants getstatic the tcnative JNI values ReferenceCountedOpenSslContext now reaches; native build verified locally in the mandrel container
- runtime-init io.netty.internal.tcnative for native image netty 4.1.136's SslContext reaches SSLPrivateKeyMethod during analysis; its JNI init fails in the builder (sslSignRsaPkcsSha1 UnsatisfiedLinkError)
- make the PII email regex linear-time on long local-part runs Negative lookbehind + possessive quantifier close CodeQL java/polynomial-redos; matches unchanged, regression test scans 500k chars
- patch every open Dependabot alert across Maven and npm manifests netty 4.2.16/4.1.136, quarkus 3.36.3, jetty 12.0.36, jackson 3.2.1/3.1.5/2.22.1, spring 6.2.19, lz4/spring-retry/postgresql pins, npm lockfiles + console bundle refresh
- ai-tools cost badge rides beforeCompletion without clobbering the router routing.* moves off the dead postProcess path and yields to RoutingLlmClient's genuine values; reset copy no longer narrates success before the approval verdict; e2e asserts the rendered chips
- merge server metadata frames by their wire shape The handler read msg.data but Atmosphere metadata frames carry top-level key/value, so routing chips never rendered from server emissions; bundle resynced to all committed consumers
- bound cost-ceiling tenant buckets and roll accrual over The map was keyed by a caller-supplied MDC tag with no cap and never decayed; 500 tags made 500 entries and one breach blocked forever
- size the compaction budget to the endpoint model, not the app default CompactionConfig.resolve(cfg, model) had zero callers, so @AiEndpoint(model=) got the configured model window - 1M instead of 128k
- register console assets by pattern so native stops pruning the SPA Both hardcoded hashes had gone stale; the old test compared the registration to itself and passed. Also: meta-gate bite test, DatabaseAgentState doc-truth
- route keyless demo mode through the pipeline runtime across the AI samples DemoResponseProducer bypasses become DemoAgentRuntime strategies (agui/dentist/orchestration/ai-tools; quarkus documents its bridge-only truth); ai-tools drives real tools and the real approval registry via new AiStreamingSession.unwrap, with HITL/tool-activity specs strengthened to match
- close open text and tool frames on completion, gate post-terminal emits Pipeline dispatches never emitted TEXT_MESSAGE_END (only the agui sample's hand-rolled TextComplete did) and a dangling TOOL_CALL_START leaked on complete; both AG-UI sessions now close innermost-first and drop frames after RUN_FINISHED/RUN_ERROR
- route the ai-chat demo fallback through the framework dispatch seam The @Prompt short-circuit bypassed DispatchDecorators, so no key meant no dev-inspector/tape/metrics; SB3 starter gains the inspector for parity
- gate the dev inspector on its own type, not a neighbouring module Top-level placement broke servlet-only apps with NoClassDefFoundError; the coordinator gate silently skipped the recorder
- install the dev inspector without requiring the coordinator The bean sat inside the coordinator-gated config, so plain AI apps recorded nothing despite the flag
- relay a worker-observed interrupt across the bounded dispatch hop An interrupt raised inside the agent body now reaches the coordinating thread so refineUntil stops at its turn boundary
- unify dispatch decorator stacks behind one shared composer Budget+confidence now on @AiEndpoint; cost+lineage+dev-inspector now on the pipeline path; parity test pins the order
- HTTP-layer retry with Retry-After in the shared SSE base 429/500/502/503/408 now retried for Anthropic and Cohere; error emitted once after budget; cancel-aware bounded backoff
- rag-chat queries the real vector store via similaritySearch Endpoint + @AiTool paths ride SpringAiVectorStoreContextProvider in keyed mode; keyword provider keeps only the A04 demo doc
- add opt-in tool-output injection screen; downgrade OWASP A04 to PARTIAL Screen at the shared finishAndEmit seam (rule-based, fail-closed, audited); matrix prose no longer claims tool outputs are stripped by default
- honor AgentLimits.timeout on the synchronous call path Bound call()/pipeline dispatch on a per-call VT executor; propagate the circular-dispatch guard across the hop
- stream tokens live, resume on resubscribe, emit error frames
- use managed langchain4j version in orchestration-demo Hardcoded 1.15.0 crashed the tool+prompt-cache path; add sample-pom version lint
- state the annotation-discovery limitation next to the native claims The runtime boots natively but classpath scanning finds no @ManagedService/@AiEndpoint/@Agent class
- drop the AI dispatch job until annotation discovery works natively AnnotationDetector reads .class files, so no @AiEndpoint/@Agent class is found in a native image
- watch every module the native samples depend on checkpoint/admin/agent/channels/skills could break a native image without triggering the lane that builds it
- dispatch a real agent turn under Native Image Both existing native targets have zero AI call sites, so the lane only proved a server starts; this one asserts assistant content keylessly via DemoAgentRuntime
- handlebars 4.5.4
- vitest + coverage-v8 4.1.10 616 tests green; lockfile updated via npm@11 (npm 10.9 arborist crashes on the esbuild override graph)
- refresh atmosphere.js dev-dep lockfile ranges types/node, vitest coverage, eslint, prettier, react, svelte, vue patch/minor updates; 616 tests green
- keep jsdom on 29.x — 30.x needs node >=22.13 and the test matrix still covers node 20 616 tests green on 29; the node-20 matrix decision is separate
- bump actions/setup-node to v7 and action-gh-release to v3
- handlebars 4.5.3, central-publishing-maven-plugin 0.11.0
- bump jsdom to 30 and the console frontend vite/vue toolchain marked 18.0.7, vite 8.2.0, plugin-vue 6.0.8, vue-tsc 3.3.9; typescript stays on 6.x (tsup's rollup-plugin-dts cannot drive the TS7 native port); console bundle regenerated
- align Quarkus version mentions with the 3.36.3 pin
- drive PgVectorContextProvider against a live pgvector container Every RAG connector test mocked the transport, so nothing had proven the SQL, the vector cast or distance ordering; hard-fails under CI rather than skipping
- drift-log entry — full SHA synthesized from a short prefix in a watcher command
- make playwright-install retries wait for the dpkg lock instead of failing instantly timeout 300 kills npx but not the sudo'd apt-get, which keeps holding the lock; DPkg::Lock::Timeout lets later attempts recover
- pin the litellm factory base URLs via a package-private baseUrl() accessor Wire-level spec comment now states it drives builder() directly since the factory cannot take a mock HttpClient
- trim concept density in the Why/Scope tables, surface @Agent code earlier Orchestration/Memory rows link reference docs instead of inlining internals; Terminology moves below @Agent
- wait for the console composer before sending in multi-client The Connected badge reports socket state, not composer readiness; a send in that gap was discarded and the list stayed empty
- pin MS YAML conformance diff to the last pre-ACS upstream commit Upstream 8149ebf93d deleted the policy-as-code examples for ACS manifests; the pin keeps the byte-for-byte claim testable
- drive dev-inspector via the decorated endpoint, exact-match MCP Tools PromptCacheDemoChat builds its own AiPipeline so DispatchDecorators never records it; 'MCP Tools' also matched the 'No MCP tools' empty state
- assert the web_search tool's own output vocabulary in the startup-team spec The sample now uses the built-in fail-closed web_search tool; 'search results' matched only the removed JSoup scrape
- pin maven-shared-utils into native-maven-plugin realm CI runners' plugin realm dropped it; native lane failed with missing MessageUtils
- allowlist Quarkus @DefaultBean doc symbol for the checkpoint-producer README
- pin Jackson 2 databind/core 2.22.1 and json-smart 2.5.2 Module-local patch pins for CVE-2026-54515 and CVE-2024-57699 pulled transitively by temporal-sdk/temporal-testing 1.30.1
- bump version to 4.0.63
- prepare for next development iteration 4.0.64-SNAPSHOT
- offline-queue badge with queued suffixes and WT-to-WS fallback resubscribe
- Rooms + Observability tabs; spring-boot-chat converted Framework-owned /api/admin/rooms over RoomManager + hasRooms/hasActuator gates; room dialect fixes (join latched until subscribe resolves, protocol/tracking framing off, RoomMember-shaped join_ack); presence, cross-member delivery, both tabs browser-proven over WebTransport
- room picker, presence, Room Protocol; classroom converted console-endpoints renders a pre-connect picker, presence frames drive the online chip, console-room joins RoomProtocolInterceptor endpoints with sinceId cursors; collaborative streaming browser-proven across two pages
- multi-agent fleet roster + activity strip; startup-team on the Console CoordinatorProcessor publishes live fleets into the framework property bag and CoordinatorController reads them via supplier (the /api/admin/coordinators wiring was a dead empty map); the console renders the runtime-truth roster on the welcome screen and per-agent steps during coordinations
- ai-chat and ai-tools on the Console with WebTransport-first connect /api/console/info gains a runtime-truth webTransport block, the console CSP allows the live HTTP/3 sidecar origin (it silently blocked WT before), routing cost/latency chips render from metadata events; bespoke React frontends deleted
- chat (WAR) and embedded-jetty-websocket-chat demo through the Atmosphere Console Both bare-Jetty samples ship gate-synced console bundle copies + static /api/console/info servlets; bespoke React bundles and stale committed asset hashes deleted, / redirects
- quarkus-chat, mcp-server and rag-chat demo through the Atmosphere Console Bespoke React frontends deleted, / redirects to /atmosphere/console/ with per-sample subtitle+endpoint config; rag-chat's root UI had referenced a nonexistent asset bundle
- grpc-chat demos through the Atmosphere Console over Connect-JSON Bare-Jetty sample ships a third gate-synced console bundle copy + a static /api/console/info servlet selecting the grpc adapter; bespoke Connect-web React frontend deleted, / redirects
- spring-boot-agui-chat demos through the Atmosphere Console Console drives the real AG-UI named-SSE wire via console-transport=ag-ui (bespoke React UI deleted, / redirects); adapter probes the origin root so connect never red-logs a 405; Playwright UI lane repointed at the Console
- spring-boot-a2a-agent demos through the Atmosphere Console Console drives the real A2A wire via console-transport=a2a (bespoke frontend deleted, / redirects); a2a/agui handlers now classify as ai mode; adapter tolerates the SSE layer's data: re-framing and surfaces failed-Task text
- gRPC chat transport adapter over Connect-JSON Speaks ConnectProtocolServlet's JSON mode (enveloped connect+json Subscribe, unary json Send) with ACK-gated open, capped resubscribe and broadcast rendering - no protobuf/codegen dependency
- A2A and AG-UI chat transport adapters as lazy chunks Built against the server wire shapes (result.artifactUpdate parts / named-SSE AgUiEventMapper inverse) with unary fallback + terminal-path completion; widens ConnectionStatusOptions.initialTransport to ConnectionTransportName
- console-transport parity on /api/console/info quarkus.atmosphere.console-transport + atmosphere.console-transport (boot3) validated to atmosphere|grpc|a2a|ag-ui, unknown falls back to atmosphere, mirroring the Spring Boot 4 starter
- pluggable ChatTransport seam behind the chat renderer Extracts the Atmosphere WS wire (framing, auth, send dialect) from useAtmosphereChat into a ChatTransport selected via /api/console/info transport; foreign adapters (grpc/a2a/ag-ui) fail loud until shipped
- console-transport property + /api/console/info transport field
- atmosphere-checkpoint-temporal — run Workflow
on a Temporal service DurableExecutionProvider adapter: steps as Temporal activities in the calling JVM, CheckpointStore snapshot parity, e2e on the Temporal test service; pins grpc-api alongside the other grpc artifacts - port the session-tape admin surface + content-read-auth gate to SB3 Tape runs/steps/replay endpoints + TapeAdminSupport + hasTape probe, gated by a ported AdminApiAuthFilter (content-read default-deny, Inv#6); ai-chat TapeLifecycleE2ETest now runs on both SB4 and SB3
- visualize the tape coordination tree as a Vue Flow node-graph Replay tab renders the coordinator + fan-out agents (edges by parentRunId) via a pure, unit-tested BFS layout; e2e-verified in the console under the strict nonce CSP with zero violations
- clear during a streaming reply no longer lets late deltas resurrect a bubble Discard flag drops stream events until the cleared stream terminates; clear also resets the agent strip and stats; bundles resynced
- agent-step handler reads the agent name from the nested AgentStep payload The wire shape is {stepName, data:{agent}} so the fleet activity strip never rendered; bundles resynced
- classroom spec lands on the Console; samples no longer claim hasFrontend
- heal WebTransport reconnect chain and drain offline queue on first open
- deterministic conversational default for no-skillId requests Free-text chat routed to whatever skill registered first (getDeclaredMethods order is JVM-arbitrary), nondeterministically hitting parameter-shaped skills and returning empty streams; prefer the single String-message skill on both stream and unary paths
- route Workflow.run() through DurableExecutionProvider.resolve() A ServiceLoader-registered engine adapter (Temporal/DBOS/Restate) now takes over without caller changes; contract test pins takeover + fallback
- enforce skill-file guardrails as admission scope on @Coordinator @Coordinator advertised ## Guardrails on the A2A card but enforced only @AgentScope; shared ScopePolicyResolver gives it @Agent's skill-beats-annotation precedence
- make annotation checks portable across ripgrep versions rg 14.1.0 (ubuntu-latest apt) matches nothing for an optional group containing a dot, so the qualified-@Disabled fix passed locally and no-op-ed in CI; also stop the harness reverting its own subject
- stop three validation checks from passing on empty input Refuse to run without rg, assert allowlists parse non-empty, move the wiring-site filter out of a stdin-stealing heredoc, and count with grep -c so a clean tree is not 1 finding
- fail architectural validation on every finding instead of warning Deletes the advisory tier, adds comment-aware scanning so Javadoc examples and enum constants stop being false positives, authorises CrewAI tool callbacks with a per-run token, and revives an offer() check dead since 68fdaf598d
- scope the tape lifecycle E2E to Spring Boot 4 (SB3 starter lacks tape admin routes) spring-boot3-starter's AtmosphereAdminEndpoint has no /api/admin/tape/* routes, so exclude TapeLifecycleE2ETest under -Pspring-boot3 until that parity gap is closed
- protect WEB-INF/META-INF on grpc-chat's Jetty static handler + CI lint grpc-chat served its frontend via DefaultServlet without setProtectedTargets; add it (matching embedded-jetty) plus an architectural-validation check failing any samples/ Jetty static-server that omits the guard
- remove unnessary docs
- stage sweep pathspecs one-by-one so an unmatched glob cannot strand the release commit docs/ lost its last subdirectory .md and 'docs/**/*.md' fataled the whole git add after Central had already published 4.0.63
- resync committed bundles after the atmosphere.js 5.0.39 dev-version bump
- repoint agent-scope-on-coordinator claim evidence at ScopePolicyResolver The shared-resolver refactor (092f1460f9) replaced the direct ScopePolicyBuilder.build call the gate greps for
- prepare next development version 5.0.39
- drop the per-sample frontend build job
- retarget sample specs to the Console UI they now serve
- probe Temporal readiness with curl GET + CLI health, not wait-on HEAD The UI server ignores HEAD so wait-on timed out against a healthy server; also gates on the gRPC frontend so the adapter's 30s failed-probe backoff cannot race startup
- resync committed bundles after rebase onto main
- fingerprint-gated bundle sync for the committed sb3/quarkus consoles sync-console-bundle.sh + architectural-validation gate close silent drift; refresh brings the Tape tab, MCP sandbox.html and the ChatTransport seam to both runtimes
- Temporal-adapter Playwright lane — assert the run in Temporal's own UI One-shot runner (fails fast unless the temporal provider ran it) + spec pinning type/queue/step-activities/result; foundation-e2e boots a Temporal dev server via the CLI
- refresh the console bundle so SB3 shows the Tape tab + graph Replace the stale SB3 console with the current build (Vue Flow tape graph); it self-gates tabs to SB3's real capabilities (Chat/Sessions/Tape) — e2e-verified on SB3, zero CSP violations, no broken tabs
- Playwright regression for the tape coordination-graph, CSP-guarded Boots startup-team, replays the coordinator, asserts the Vue Flow graph renders multi-node with zero CSP violations; opens the tape read-gate in the fixture + notes the graph in modules/ai/README
- document skill-file guardrail enforcement on Coordinator.skillFile
- declare directly-used Jackson artifacts instead of leaning on transitives dependency:analyze: jackson-core in ai/agent/checkpoint, jackson-annotations in coordinator, jackson-databind in verifier were compile-referenced but undeclared
- prove every architectural-validation check fails on a violation Adds a 25-case injection suite asserting WHICH check fires, fixes two regexes that could never match the spellings their extractors targeted, and gates the CrewAI sidecar pytest in CI
- end-to-end tape lifecycle — record, admin-read, replay, extract @SpringBootTest drives a taped turn through the installed recorder, reads it over the gated HTTP admin surface, replays it, and extracts one training example — no live LLM or WebSocket transport needed
- guard always-active controllers against optional atmosphere-ai in signatures Generic autoconfig-registry scan of every starter controller + ai-free durable-sessions boot smoke reproduce the NoClassDefFoundError trap the console Tape tab hit
- bump version to 4.0.62
- prepare next development version 5.0.38
- prepare for next development iteration 4.0.63-SNAPSHOT
- session-tape replay — reconstruct a run and a multi-agent coordination tree TapeReplay reconstruct/reconstructTree (no model) + parentRunId linkage (withParentRun→A2A metadata) + tool-agent dispatch tape; gated /api/admin/tape/runs/{id}/replay + Console Replay tab; fixes A2A metadata-inherit and Resilient/Intercepting proxy propagation; docs (tutorial 36 + reference/tape + READMEs)
- Tape tab — browse recorded session tapes in the Atmosphere Console Adds gated /api/admin/tape read endpoints (runs + steps, content-read-auth per Inv#6) + hasTape runtime-truth flag + a Vue Tape tab (runs list + step detail) in the spring-boot-starter console
- tape → training data — self-contained tape + TapeTrainingExtractor Record the input prompt as a tape step on both dispatch paths so the tape is a (prompt→completion) record; TapeTrainingExtractor folds runs to chat-JSONL, TapeDatasetCli emits it; spring-boot-ai-chat demos the durable tape
- session tape — durable typed AiEvent stream, resume, admin read Records the AiEndpointHandler + AiPipeline session seams to SQLite/in-memory TapeStore; late-bound runId, crash-resume segments, atmosphere_read_tape gated REQUIRE_PRINCIPAL; opt-in (atmosphere.ai.tape.enabled) across both Spring starters + Quarkus
- opt-in security-headers filter for app routes; mcp-server consumes it
- in-process sandboxed eval tool (Rhino) — deepagents eval parity Container-free 'eval' JS tool: sandboxed Rhino scope (deny-all ClassShutter, no java/Packages bridge, interpreted-mode instruction + wall-clock budget, fresh scope per call), default-off and runtime-truth gated via an optional dependency, registered at the shared agent/endpoint tool site. Closes the last deepagents capability gap; 14 tests pin the sandbox.
- add delete + rename file tools — deepagents file-tool parity The built-in filesystem floor grows from six to eight tools: delete (ToolKind.DELETE, approval-gateable) and rename, both bounds/traversal-guarded over the conversation-scoped AgentFileSystem, closing the delete gap vs LangChain deepagents. Updates every count/phrasing across code, tests, READMEs (six→eight), and the e2e tool-count pins (dentist + orchestration now log tools: 11 = 2 user + 9 harness) — both verified empirically from a booted sample.
- wire governance decision log to Postgres/Kafka audit sinks Config-gated auto-config installs JdbcAuditSink/KafkaAuditSink so admit+deny persist
- thread inbound image input onto the model request (vision)
- discover Cedar/Rego PolicyParser SPIs on the governance reload path
- wire configurable backpressure drop-policy into the broadcaster write path
- install path for the 5 missing governance admission stages PERMISSIONS.md now wires all 7 stages (rate-limit, concurrency, message-length, time-window, kill-switch)
- one-dependency streaming @Agent chat sample proving the blog claim Add spring-boot-one-dep-agent; make atmosphere-ai-spring-boot-starter pull the web server non-optionally so one dependency boots a running streaming chat app.
- add Checkpoints tab to admin Console over durable-run store
- isolate optional tape types from always-active admin/console signatures Direct atmosphere-ai tape refs were force-loaded by Spring getDeclaredMethods, crashing non-AI samples at startup; reads move to TapeAdminSupport + reflective hasTape probe
- protect WEB-INF/META-INF in embedded-jetty chat sample
- honor SERVER_PORT env in kotlin-dsl-chat + embedded-jetty-websocket-chat
- nonce-based strict CSP for the console + harden mcp-server root SPA
- harden CORS credentials, console headers, A2A JSON charset, error disclosure
- map spring-boot-one-dep-agent into the release-gate smoke shard Unmapped sample tripped the no-silent-caps gate; smoke tier (boot jar + GET /atmosphere/console/ == 200) verified locally
- keep ai-chat content-read secure by default; opt out only in the real-LLM demo run
- ms-governance-chat opts out content-read-auth so its Decisions tab renders token-less
- reject SSRF to internal targets in push-notification webhooks Deny loopback/private/link-local/metadata by default (delivery-time re-check for DNS rebinding); opt in via org.atmosphere.a2a.pushAllowPrivateTargets on trusted networks
- ai-chat opts out content-read-auth so the console Decisions tab renders token-less
- auth the governance/decisions poll (read-plane fail-close regression)
- bump rhino 1.7.15 to 1.7.15.1 (CVE-2025-66453)
- pin logback 1.5.37 in sample poms (CVE-2026-10532) samples re-import the Spring Boot BOM (logback 1.5.34); a direct version pin forces the patched line
- bump logback 1.5.33 to 1.5.37 (CVE-2026-10532 object injection)
- patch DoS vulns in test deps + pin org.json (Dependabot) ws 8.19→8.21 (CVE-2026-48779), @grpc/grpc-js 1.14.3→1.14.4 (GHSA-5375-pq7m-f5r2), org.json pinned 20250517
- add justified unrestricted @AgentScope to one-dep ChatAgent
- require auth for recorded-content admin reads by default governance/decisions, audit, journal expose prompt/response + coordination content — default-deny, Spring+Quarkus parity, opt-out content-read-auth-required
- sync capability skillcards + README to the 22-capability set
- make compose-with-native-frameworks layering explicit across READMEs
- tempest campaign coverage overstated — ~8/32 genuinely tested, not 21
- document the unauthenticated channel posture and production hardening
- log drift — swept setup-java hardening on a stale local tree Enumerated verify-signature targets before rebasing onto origin/main; gate is fetch+rebase then re-enumerate before any push-bound sweep.
- GPG-verify Temurin JDK archives across all setup-java steps Fan out the dependency-submission verify-signature pilot; Oracle JDK 26 matrix leg gated off, graalvm skipped (both unsupported).
- run the coverage-map gate on push/PR, not just nightly A new samples/ dir missing its release-gate map entry now fails the introducing PR (build-free --list check) instead of the next nightly run
- bump the maven group across 26 directories with 1 update (#2712)
- bump testcontainers.version from 1.20.6 to 1.21.4 (#2702)
- bump quarkus-langchain4j.version from 1.9.2 to 1.11.2 (#2704)
- bump tools.jackson.core:jackson-databind (#2703)
- bump the sample-frontend group across 15 directories with 2 updates (#2707)
- bump actions/github-script from 7 to 9 (#2706)
- bump codecov/codecov-action from 6 to 7 (#2705)
- pilot verify-signature on the dependency-submission lane
- shared sample config change to fix one e2e broke another on the same fixture
- admin read-plane fix verified via edited specs, not the console consumer it broke
- lead with streaming again — demote deep-agent row, tighten hero Deep-agent Why row moves below streaming/adapters; LangChain deepagents comparison stays only in the harness subsection.
- same-session recurrence — read -q dependency:tree empty result as dependency absent
- make the eval interpreter pluggable via the EvalEngine SPI Extracts a ServiceLoader EvalEngine SPI (highest-priority-available wins, like AgentRuntime); Rhino/JavaScript ships as the default at priority 0, alternatives plug in by adding a jar. Rhino internals move to RhinoScriptSandbox so the adapter signature stays optional-dep-clean. 5 tests pin priority-override + availability-gating.
- wrong 'qwen too weak' call from 0 findings without checking the LLM was reached
- click-through demos for tool-output offload + composite FS routing personal-assistant README now has reproducible offload (LLM_TOOL_OUTPUT_OFFLOAD_THRESHOLD=200 → read_file result offloads to tool-output/) and composite-routing (LLM_FILESYSTEM_ROUTES=memory/=dir → prefix lands in durable backend, rest stays per-conversation) walkthroughs — both browser+disk-proven on Ollama, matching what a user will see in the Workspace tab.
- showcase the task tool, offload, and composite FS routing personal-assistant README documents the dynamic subagent-spawn task tool (the @Coordinator harness registers it alongside delegate_task) with a copy-paste Ollama flow — browser-proven end to end; coding-agent README adds tool-output disk offload (default-on) and composite filesystem routing (atmosphere.ai.filesystem.routes) so users can run the newest deep-agent features, not just read about them.
- allowlist java.sql.DriverManager Javadoc ref in the audit DataSource
- drop redundant MULTI_AGENT_HANDOFF, wire Koog MODEL_ENUMERATION
- restore broadcaster tagline, surface deep-agent harness + MCP/A2A/AG-UI
- false 'pinned version' fact in Embabel comment shipped in 4.0.60/4.0.61
- bump version to 4.0.61
- prepare next development version 5.0.37
- prepare for next development iteration 4.0.62-SNAPSHOT
- governance as a learning signal — Prefer decision, feedback loop, durable recall PolicyDecision.Prefer soft-preference + native preference type + GovernanceFeedbackInterceptor (re-injects deny/prefer guidance into the turn) + opt-in durable provenance memory across Spring/Quarkus/bare-JVM; real-LLM sample (spring-boot-ai-chat) + Ollama e2e; console PREFER view; real-LLM CI consolidated on Ollama.
- tool-output disk offload + composite AgentFileSystem routing Large built-in tool results (>8000 chars, threshold-gated, sysprop/env overridable) spill to the agent workspace and the model gets a preview + read_file pointer — default-on at the tool choke point, fail-safe (never throws/loses data, honors workspace bounds). AgentFileSystemProvider composes a CompositeAgentFileSystem over the per-conversation workspace when durable prefix routes are configured (atmosphere.ai.filesystem.routes, off by default), routing the eight ops by longest-prefix with per-route bounds. Closes the two minor deepagents parity gaps. 3+15+2 tests.
- task tool — dynamic ephemeral subagent spawn (deepagents parity) The @Coordinator harness now registers a 'task' tool alongside delegate_task: it spawns a general-purpose subagent with an isolated context/workspace (fresh conversation, own plan store + bounded file store), runs one subtask with the harness floor, and returns its final report. Governed (pre-admission, fail-closed), depth-bounded across the spawn thread, time-bounded with cleanup; 7 tests + preset pin. Closes the last parity gap vs LangChain deepagents.
- native tool-loop enforcement via Embabel 0.5.0 inspector/transformer API The stale comment claimed 0.3.5 lacked the seam; 0.5.0 ships withToolLoopInspectors/withToolLoopTransformers, so EmbabelToolLoopBridge strips tool calls on the transformer seam at the cap (the real stop) and mirrors ToolLoopGuard's breach on FAIL, honoring COMPLETE_WITHOUT_TOOLS natively; wire guard kept as backstop, native path only, 7 tests.
- env/sysprop LLM knobs win over RUNTIME.md pins A workspace RUNTIME.md model/mode/base-url/api-key pin was overriding an operator's explicit LLM_MODEL/LLM_MODE/... env (or system property), so pointing the personal-assistant sample at Ollama 404'd on the pinned gemini model; pins are now defaults an env override beats. Regression + env-lookup seam keep the test hermetic against ambient .envrc vars.
- log drift — feature called 'documented' while published docs were stale Governance learning-signal PolicyDecision.Prefer shipped but atmosphere.github.io reference listed only Admit/Transform/Deny; caught on the completion-number question, external docs now published.
- surface the batteries-included deep-agent harness A plain @Agent is a deep agent out of the box (memory, write_todos plan, virtual filesystem, task sub-agent spawn) — add a Why-Atmosphere row and a dedicated subsection linking the harness docs and the LangChain deepagents comparison.
- note governance learning-signal loop in module README Points at governance-policy-plane.md + the spring-boot-ai-chat sample; adds the native prefer vocabulary + durable-recall flag.
- rewrite compliance matrix notes in plain operator language EU AI Act / HIPAA / SOC2 rows; class names and config move to the evidence disclosure
- deep-agent harness primitives on a @Coordinator Deterministic Playwright spec (demo mode, no live LLM) pinning that the personal-assistant coordinator registers the dynamic subagent-spawn task tool + delegate_task + the write_todos floor, and /api/console/info reports planning/filesystem/delegation ACTIVE — the wiring a real turn depends on, guarded in the always-on lane.
- rewrite OWASP matrix notes in plain operator language class names, config keys and roadmap labels move to the evidence disclosure
- bump version to 4.0.60
- prepare next development version 5.0.36
- prepare for next development iteration 4.0.61-SNAPSHOT
- native plan bridges persist to AgentPlanStore under the floor's key Embabel GOAP and Koog planner mirrors now also put() every plan under the same (agentId, conversationId) the write_todos floor uses, so the admin plan endpoint and Workspace stored view work for opted-in native surfaces; best-effort with WARN on store failure, pinned by persistence + failure-isolation tests in both bridges.
- koog native plan observation, embabel bounded file tools, plan-event correlation KoogPlanner dispatch branch + KoogPlanBridge mirror planner lifecycle into PlanUpdate (capability deliberately undeclared: koog plans exist only when the caller supplies a planner, so the write_todos floor must stay); AtmosphereFileTools implements Embabel's FileTools over the bounded conversation store (VIRTUAL_FILESYSTEM declared); PlanUpdate now carries conversationId/agentId at every emitter so the console Workspace tab correlates live plans to stored state one-click.
- planning + virtual-filesystem harness primitives; console broadcast fix write_todos and bounded ls/read/write/edit/glob/grep tools attach by default on every tool-calling runtime (Harness PLANNING/FILESYSTEM); AgentScope PlanNotebook, Embabel GOAP and Alibaba todos delegate via AiCapability.PLANNING while ADK artifacts and the Anthropic memory tool expose the store via VIRTUAL_FILESYSTEM; console gains a Workspace tab plus a broadcast-mode fix from a 29-sample browser sweep (outbound {author,message} envelope, event-less inbound frames render, cross-client Playwright regression); browser-proven with a real model.
- Harness feature set on @Agent/@Coordinator/@AiEndpoint replaces the deep-agent boolean @Agent and @Coordinator are batteries-included by default (harness() = {ALL}; empty array opts down to a bare loop) while a bare @AiEndpoint opts in per endpoint; the app-wide atmosphere.ai.harness.enabled flag is tri-state with explicit false as a kill switch beating every annotation; user-facing config keys and the console runtime-truth block rename deep-agent to harness; HTTP + Playwright e2e pin default-on, opt-in and kill-switch on booted apps.
- deep-agent harness on @Agent(deepAgent) + wired @SandboxTool @Agent(deepAgent=true) — or atmosphere.ai.deep-agent.enabled app-wide — attaches long-term memory, a prompt-cache default, selectable compaction and fleet delegation with per-primitive runtime-truth at /api/console/info; @SandboxTool routes a tool method through a framework-owned Sandbox; fixed the built-in runtime model fallback so LTM fact extraction works (browser-proven cross-session recall); Spring/Quarkus/servlet parity; personal-assistant + coding-agent samples converted.
- @Command slash commands work on @AiEndpoint, not only @Agent New AiHandlerDecorator SPI lets atmosphere-agent wrap any @AiEndpoint that declares @Command methods with the same command router the @Agent path uses; rag-chat console /sources is now an instant KB listing instead of falling through to the LLM.
- honor @AgentScope on @Agent classes and lint their scope posture
- client-reachable durable crash-resume via X-Atmosphere-Run-Id reconnect
- lead quarkus-ai-chat with @Agent instead of @AiEndpoint
- lead spring-boot-ai-chat with @Agent instead of @AiEndpoint
- lead spring-boot-channels-chat with @Agent instead of @AiEndpoint
- add atmosphere-ai-spring-boot-starter for one-dependency @Agent apps
- durable agent runs with deterministic replay across runtimes
- auto-wire default CheckpointStore and ContextProvider beans in-memory defaults via @ConditionalOnMissingBean with startup warnings; all six families now self-wire
- prove atmosphere-admin-bundle self-wires the six families
- add kotlin-dsl-chat proving the Kotlin DSL + coroutine extensions
- prove Spring AI setChatClient + defaultAdvisors + per-request advisors
- deliver audio input to the runtime via stream(message, parts) MultiModalChat forwards audio: prompts as Content.Audio input; delivery test asserts the runtime context carries the audio part
- add @AiEndpoint(broadcastReply) to fan one reply out to a room
- add passivation-agent sample proving pause/resume Snapshots a paused conversation to a CheckpointStore and resumes it from the restored history; PassivationDeliveryTest asserts the round-trip.
- gate a money-moving refund tool behind @RequiresApproval
- enforce @Agent scope from skill ## Guardrails on web and pipeline paths A skill's ## Guardrails lines become an enforced ScopePolicy (tier from optional scopeTier frontmatter, default embedding-similarity), prepended on both the web streaming and A2A/AG-UI/channel pipeline paths.
- confine @AgentScope on the web streaming path too (Mode Parity #7)
- enforce @AgentScope confinement on the @Coordinator pipeline Extract reusable ScopePolicyBuilder; prepend the scope policy ahead of installed policies.
- wire OpenClaw workspace extension files into the processors AgentProcessor/CoordinatorProcessor consume RUNTIME/PERMISSIONS/SKILLS/CHANNELS/MCP; PERMISSIONS denials enforced on web, A2A and channel paths
- gate admin writes on atmosphere.admin.required-role (JWT roles)
- undeclare PLANNING/VIRTUAL_FILESYSTEM — native surfaces become explicit opt-ins Each surface exists on only one of the two dispatch paths (GOAP bridge: deployed-agent; FileTools: Atmosphere-native); a static declaration suppressed the portable floors everywhere, leaving the uncovered path with no plan/file surface behind an ACTIVE(native:embabel) label. Floors now own AUTO on every path; planning/filesystem=native attach the native surfaces (same reasoning as Koog). Snapshot+SKILLCARD+contract pins updated.
- keep the workspace owners probe open, gate only plan/file content
- harden planning + virtual-filesystem harness — bounds, scoping, runtime truth, auth
- don't let an OTel GenAI meter conflict crash the request path MicrometerAiMetrics dual-emits gen_ai.client.operation.duration and token.usage; when a co-resident instrumentation (quarkus-langchain4j) already owns those OTel names with different tag keys, Micrometer/Prometheus rejects the registration and the exception surfaced as an in-stream error frame (paid-nightly Gemini disconnect-recovery). Back off the dual-emit once on conflict, keeping the atmosphere.ai.* series; regression test drives a registry that rejects the registration.
- harness-aware CI lanes, tool-count truth, governed-dispatch rate budget Real-LLM lanes install the quarkus-ai-chat module closure (deployment verification needs installed artifacts, not a stale cache); orchestration spec pins the new 9-tool truth (2 user + 7 harness); the startup-team rate policy is sized for governed fan-out (one prompt = five metered tickets) and the activity spec waits for genuine connection and tolerates a spent window.
- harness review — attach-time runtime truth, delegate_task user guard, mode parity
- append grounded facts after the system prompt so provider prefix caches keep hitting time.now renders at minute granularity; schema/confidence appends splice in before the trailing fact block so volatile facts stay the suffix.
- @Coordinator classes now register on Quarkus (Mode Parity) Add @Coordinator to the build-time annotation scan and index atmosphere-coordinator when the app declares one, so CoordinatorProcessor is discovered and fleet coordinators register like on Spring Boot.
- align OpenTelemetry deps so spans reach Jaeger; pin a real Jaeger image The parent pom managed only opentelemetry-api (1.63) while sdk/exporter fell to 1.55, so the OTLP exporter died with NoClassDefFoundError InstrumentationUtil and no span exported; import opentelemetry-bom to align all artifacts and pin jaegertracing/jaeger:2.19.0 (the :2 tag does not exist). New OtlpExporterLinkageTest reproduces the export-path skew without Docker.
- broadcast the reply to the whole room, not just the asker The @AiEndpoint was missing broadcastReply=true, so streamed frames unicast to the origin while presence fanned out; a foundation-e2e spec pins fan-out to same-room members and isolation from other rooms.
- ms-governance-chat out-of-box + policy bridge merge + manual-gate postResponse
- explicit client bindings beat the demo runtime and survive auto-configuration setChatClient/setModel now mark an explicit binding (demo fallback yields keyless) and autoconfig offers instead of clobbering, so a caller-built ChatClient keeps its defaultAdvisors; new keyless foundation-e2e spec pins the advisors sample contract.
- per-transport DSL broadcast delivery; kotlin-dsl-chat WS container + logback-core Raw HTTP subscribers were never flushed, WS upgrades 501'd (no jakarta.websocket container) and the shaded jar dropped logback-core; new foundation-e2e Playwright spec pins all three from the packaged jar.
- guardrail scope no longer self-blocks an agent's own domain
- pin opentelemetry-api to 1.60.1 to match -common
- capture durable run-id in transport for reconnect resume
- close OpenTelemetry scope in postInspect to stop context leak Suspended/cancelled requests left the span thread-local-current on pooled threads (#2643).
- pin mcp-core 1.0.1 + handlebars 4.5.2, hold MCP SDK to 1.x Closes GHSA-r4gv-qr8j-p3pg (handlebars) and the mcp-core follow-up advisory; 9 alerts.
- construct SQLite run journal reflectively for native image
- reach SQLite run-journal factory reflectively for native image
- defer QuarkusSqliteRunJournalFactory to runtime init for native image
- remove duplicate jackson-annotations dependencyManagement entry The Jackson CVE pin re-declared jackson-annotations at ${jackson2.version} (2.22.0) alongside the existing ${jackson-annotations.version} (2.22) entry, a duplicate key Maven warns threatens build stability; keep the proven 2.22 pin (resolves; Jackson-3.x >=2.21 compat) and drop the redundant 2.22.0 one.
- allowlist ConditionalOnClass/SpringBootTest for cherry-picked READMEs
- embedding scope guardrail degrades to rule-based when embeddings fail A failed embed call (e.g. the provider has no matching embedding model — Gemini 404s on text-embedding-3-small) previously errored and blocked every request, bricking any @Agent with a restrictive EMBEDDING_SIMILARITY scope; it now falls back to keyword rule-based enforcement so the agent stays usable and forbidden topics are still blocked.
- add reactor-netty-http so declared WebTransport actually starts Five samples set atmosphere.web-transport.enabled=true but omitted the HTTP/3 dependency, so AtmosphereWebTransportAutoConfiguration's @ConditionalOnClass failed and the server silently no-oped while the client fell back to WebSocket; frontends rebuilt against the fixed client.
- don't surface a recovered transport-fallback as a fatal error subscribe() now suppresses the primary transport's error callback until it actually opens, so a websocket fallback that recovers a failed webtransport handshake no longer shows a stale "Opening handshake failed" banner; a genuine no-fallback failure still propagates. 608 tests green.
- guard eager runtime configure() so @Agent registers on Quarkus AgentProcessor.resolveRuntime now swallows a backend's configure() failure like AiEndpointProcessor already does, so an unready Quarkus TLS bean no longer aborts the annotation scan and drops every endpoint.
- allowlist PostgreSQLContainer for the backend-class-ref gate
- cast context_snapshot to JSONB so Postgres persists decisions
- forward stream(String,List) on DelegatingStreamingSession; scope advisors endpoint
- enforce real Cedar authorize decisions; add OPA/Cedar engine ITs Add mandatory --entities, parse plain-text ALLOW/DENY, map exit 0/2; gated real-binary integration tests + CI lane that installs the engines
- pin Jackson 3.1.4 / 2.22.0 to close CVE-2026-54512..54518 Transitive jackson-databind batch (511 alerts); annotations to 2.22.
- skip request-heavy transport tests on the Gemini free-tier leg Gemini free tier caps at ~20 requests/day, which the multi-turn, disconnect-recovery and long-polling transport tests blow through. They are provider-independent (their own skip messages say 'requires real-ollama'), so gate them behind LLM_SKIP_REQUEST_HEAVY (set on the gemini matrix leg); they keep running on Ollama every push and OpenAI nightly. A billing-enabled Gemini key flips the flag off to run them here too.
- paid lane drives gemini-2.5-flash-lite The configured key's project is free-tier for gemini-2.5-flash (20 req/day/model per the 429 QuotaFailure payload) — one nightly plus a manual dispatch exhausts it; flash-lite's free tier sustains the schedule and stays a production Gemini model.
- rate-budget real-LLM sends so the free-tier Gemini leg stays under quota Gemini free tier caps generate_content at 5 req/min/model; the paid nightly's multi-turn and recovery specs fire ~9 prompts back-to-back and 429 (relayed as an in-stream error frame). Add a file-backed rolling-window limiter (llm-rate-budget.ts, no-op unless LLM_RPM is set) awaited before each real-LLM send; the gemini leg sets LLM_RPM=4 and a shared budget file spanning both playwright steps. Ollama and OpenAI legs run unthrottled.
- scope the session-isolation spec to local Ollama Session semantics are provider-independent; the spec's rapid back-to-back prompts trip remote free-tier per-minute limits (Gemini 429 turned the sender's stream into an instant error frame on the paid dispatch), so the remote legs skip it and keep their own streaming coverage.
- pin per-session isolation and the console echo round-trip The fanout test asserted broadcast semantics @AiEndpoint never had (never ran in CI behind the advisory mask; fails identically on the 2026-07-02 pre-harness jar) — rewritten to the ai-tools-pinned contract that another client must NOT receive a private reply; the webtransport round-trip now asserts both the user bubble and the server echo the console renders.
- dentist spec pins the harness tool count Same default-on truth as the orchestration spec: 2 user tools + 7 batteries-included harness tools = 9; grep confirms no other spec pins raw tool counts.
- resilient first send in the real-LLM ws client A cold WebSocket upgrade can drop the first data frame (the raw test handler reads one line per onRequest dispatch); a single opt-in resend makes the first turn deterministic — a genuinely broken stream still yields zero events twice and fails loudly. 3x/no-retries green locally against Ollama.
- full-reactor install in real-LLM lanes (Quarkus verification on cold cache) Scoped -pl/-am builds fail Quarkus extension dependency verification when the deployment artifact resolves in-reactor on a cold ~/.m2 (same trap ci.yml's boot gate documents); install the reactor once, then package only the runnable quarkus-run.jar.
- build the quarkus module closure when packaging quarkus-ai-chat Both real-LLM lanes packaged the sample without -am, resolving its quarkus extension deps only from a stale Maven cache; the 2026-07-04 paid nightly failed the moment the cache rotated.
- assert the omnichannel channel-bridge wiring in channels-chat Replace the shallow 'Starting service [Tomcat]' check (every Spring Boot app prints it) with the headline runtime-truth: ChannelAiBridge registers the 'omnichannel' @Agent with its AI pipeline and binds it to all five messaging channels (telegram/slack/discord/whatsapp/messenger). Deterministic + keyless; external delivery still needs bot tokens.
- drop the advisory continue-on-error hack from the real-LLM + JS lanes Take the Ollama lane off the per-push path (nightly + dispatch) so it reports honestly instead of masking failures green with a red-X-that-doesn't-count; the paid lane was already scheduled; the JS coverage upload uses codecov fail_ci_if_error:false instead of a blanket mask. Only the allowlisted release-4x website-sync dispatch keeps continue-on-error.
- add headline coverage for the passivation-agent sample Drive POST /api/agent/pause -> checkpoint -> GET inspect -> POST resume; assert the keyless DemoContinuationRuntime resumes WARM (quotes the restored history, continued=true, restoredHistorySize=2) not cold, plus 404/400 boundaries. Wire the sample into the fixture, playwright config and e2e.yml.
- assert real durable-session survival across restart The restart specs only checked a fresh connection works post-restart — green even if SQLite persistence broke. Capture the issued session token via long-polling (WS doesn't expose it), restart the JVM, assert reconnecting with it restores the SAME session + sessions.db non-empty, with an unknown-token negative control; relabel the identity test that only proved the endpoint recovers.
- fix strict-mode violation in de-flaked history assertions The keyless demo reply echoes the prompt text, so getByText(prompt) matched both the user bubble and the reply (2 elements) once the @flaky tag was removed and the tests ran strict. Target .message--user by text so the user-history assertions are unique in rag-chat and unified-console.
- de-flake the console tests with a precise assistant selector Replace the broad [class*=assistant],[class*=message] locator (which also matched user bubbles, avatars and the toolbar) with the precise .message--assistant in rag-chat and ai-tools and drop the @flaky tags; the imprecise selector also let ai-tools' multi-client test pass spuriously, so rewrite it to assert the real per-session isolation (session.stream, not a broadcast room).
- validate code-as-action wiring + real sandbox execution Assert the sample boots with code_exec registered and code-as-action enabled (keyless runtime-truth); add a Docker-gated CodeExecSandboxIntegrationTest that runs real JS/bash in a container and proves the sandbox is stateful across execs — the code-as-action substrate the full browse builds on. Full LLM-driven browse still needs a paid key + container engine (infra-gated).
- include spring-boot-ai-chat in unified-console (unmask the exclusion) ai-chat was skipped as 'WS never connects in CI'; real cause was the fixture forcing auth ON while the console sent no token, so the AuthInterceptor closed every socket. Load the console with ?token= (resolveAuthToken sends it as X-Atmosphere-Auth); consolidate ai-chat auth config to application.yml (auth off default, no properties/yml conflict); de-flake the send test with a precise assistant-bubble selector.
- release-gate fnd tier ran a dormant spec hitting a nonexistent endpoint
- harden unified-console flake + rewrite stale guarded-email spec Extract a 30s WS-connect wait so a slow-but-successful console connect isn't a flake; repoint the guarded-email spec at the real Console Validation tab + POST /api/admin/verifier/check (the sample has no /agent), asserting the @Sink taint refusal and the anonymous-write 401.
- reframe as real-time event-driven framework, tighten wording
- self-guard revived specs + drop redundant clustering/wasync no-ops Fail loud (not silent-skip) when a sample jar is missing in CI; remove the kafka/redis/wasync-client test.skip placeholders — real coverage is the Java Testcontainers lane (RedisClusteringTest, KafkaClusteringTest, wasync ChatIntegrationTest).
- revive dead-skipping integration specs + add fat-jar packaging smoke Fix wrong four-up ROOT that silently skipped otel/kotlin-dsl/parity specs; assert real behavior (WS-101, logback-active, OTLP export-health); boot shade/BOM samples from their jars in sample-startup-smoke.
- release-gate lane's dual-Playwright browser-install hole (bed4859f66)
- install Playwright browsers for both e2e and integration-tests
- bump esbuild to 0.28.1 via npm overrides Resolves Dependabot GHSA-g7r4-m6w7-qqqr (dev-server arbitrary file read) in atmosphere.js and the console frontend lockfiles; logback 1.5.33 landed separately via Dependabot PR #2701.
- bump the maven group across 62 directories with 1 update (#2701)
- guard keyless web-channel answers with a foundation-e2e spec The release-gate 'swallowed messages' was a stale-socket artifact, not a defect; this spec locks in that consecutive web turns each get a demo reply.
- gate public blog claims against the released artifact blog-claims.json manifest + validate-blog-claims.sh check non-comment code evidence at the release tag and GAV existence on Central; wired into release-4x validate + post-publish; reproduces the 4.0.59 gap (10/10 claims fail, starter GAV 404)
- packaged-artifact sample E2E gate (nightly + release-4x precondition) Boots every runnable sample from its boot/runner jar and runs its Playwright or smoke coverage; release-maven now requires the sweep green.
- prime the full reactor before packaging the smoke samples
- add sample-startup smoke job booting quarkus-ai-chat and spring-boot-ai-chat
- make integration-tests lane a real isolation lane, not duplicated coverage
- wire phantom-Javadoc validator into pre-push and index Kotlin declarations Fixes the real phantoms it caught: Javadoc misnamed GuardrailAsPolicy/PolicyAsGuardrail and GovernanceFleetInterceptor; SdkTracerProvider allowlisted as OpenTelemetry SDK.
- add phantom-Javadoc-class-ref validator (allowlist-filtered)
- bump actions/upload-artifact to v7 in sign-skillcards workflow
- cover the @Agent multimodal endpoint in the quarkus-ai-chat spec
- fail packaging if the jar lacks the Console Remove dead skip.frontend wiring; the Console is always built, including under -Pfastinstall.
- add parallel Core Integration Tests lane
- gitignore .mcp.json (per-developer local MCP config)
- rebuild Console from source via frontend-maven-plugin
- assert channel allow-list is enforced at dispatch, not just stored
- bump actions/cache from 4 to 6 (#2692)
- bump actions/checkout from 4 to 7 (#2691)
- bump org.apache.maven.plugins:maven-deploy-plugin (#2698)
- bump org.xerial:sqlite-jdbc from 3.49.1.0 to 3.53.2.0 (#2699)
- bump com.h2database:h2 from 2.3.232 to 2.4.240 (#2697)
- bump undici from 7.25.0 to 7.28.0 in /atmosphere.js (#2680)
- bump protobufjs (#2676)
- bump the sample-frontend group across 15 directories with 21 updates (#2687)
- bump opentelemetry-api.version from 1.62.0 to 1.63.0 (#2694)
- bump org.mockito.kotlin:mockito-kotlin from 5.4.0 to 6.3.0 (#2646)
- bump org.apache.maven.plugins:maven-gpg-plugin (#2644)
- hold mcp-core to 1.0.x in dependabot (block minor, not just major) Keeps it on the CVE-fixed 1.0.1 force-pin; stops the recurring 1.1.x bump PRs.
- exclude kotlin-dsl-chat — its Kotlin 2.1.10 breaks the CQL extractor CodeQL's KotlinExtractorComponentRegistrar is incompatible with the Kotlin 2.1.10 compiler the sample invokes (AbstractMethodError), failing the whole analysis build; the module is a leaf demo so excluding it from the scan build loses no real coverage.
- test the full reactor instead of a hand-picked 18-module list A -pl allowlist silently dropped every new module from per-push CI — ~29 of 47 test-bearing modules (admin, channels, rag, verifier, the *-postgres modules, etc.) were built but tested nowhere except the release job. Testing the whole reactor (like release-4x.yml) means a new module is covered the moment it exists.
- end-to-end durable crash-resume cycle across reconnect and admin
- note why browser-agent keeps @AiEndpoint over @Agent
- note why ai-classroom keeps @AiEndpoint over @Agent
- drift-log the blog make-it-true closure (4 real bugs behind green stub tests)
- prove cross-node stream relay over a real Redis backplane
- prove rooms presence tracks membership over the wire Two wAsync subscribers join/leave; presence frames delivered and Room/REST membership updates
- prove WebTransport/HTTP3 wiring in startup-team sample
- prove cost/latency model routing selects the expected model Adds offline routing-cost/routing-latency profiles and a delivery test asserting the router picks frugal-mini by cost and swift-pro by latency
- prove outbound A2A JSON-RPC call from a2a-agent sample Boots the sample's own A2A server and drives a real A2aAgentTransport round trip
- prove built-in runtime threads native schema to response_format
- remove duplicate dependency-update workflow, pin tracks in dependabot Dependabot now owns all Maven PRs; in-track ignores replace the AUTO-BUMP tier.
- correct guarded-agent sample API (PlanAndVerify, not interceptor) + drift-log
- drop false MEMORY.md/memory reads from OpenClaw adapter docs
- tighten guardrail count, PII block-vs-redact, compliance-row scope
- bump version to 4.0.59
- prepare for next development iteration 4.0.60-SNAPSHOT
- screen long-term-memory writes for injection by default harden coverage evidence gate; relabel opt-in OWASP/compliance rows honestly
- bump Spring Boot, LangChain4j, Embabel, ADK, Spring AI Alibaba Embabel 0.5.0 adds EmbeddingService.pricingModel; test stub reports ALL_YOU_CAN_EAT.
- record coverage-overstatement drift + self-referential-gate rule
- add obsidian skills + atmosphere-vault docs routing
- align capability comment, sample runtime defaults, and XSS skip note with reality
- add workflow_dispatch to Core and Doc Version Guard
- bump version to 4.0.58
- prepare for next development iteration 4.0.59-SNAPSHOT
- default-on RAG injection-safety wiring across runtimes Screens retrieved RAG documents for indirect prompt injection before the LLM (fail-closed RULE_BASED/DROP); wired for @AiEndpoint, Spring Boot 3/4, and Quarkus with console runtime-truth and a poisoned-doc sample.
- pin rag-chat getting-started to released 4.0.57
- stage doc sweep and fail-fast on doc-version drift before publish
- bump version to 4.0.57
- prepare next development version 5.0.35
- prepare for next development iteration 4.0.58-SNAPSHOT
- provider-native structured output across 9 runtimes
- guard expo stats render against undefined token metrics
- unblock MCP Apps sandbox CSP and stop optional-tab 404 probes
- expose analyzer as @AgentSkill so approve happy path works
- expect analyzer's headless A2A registration
- note path-scoped native structured output for Spring AI, Koog, ADK
- enforce Atmosphere doc matches the released version
- retry fetch+rebase+push so a lost race can't red a green release
- apt-get update before installing libxml2-utils so the delisted stale version isn't fetched
- rebase before pushing JS dev-bump so it can't lose the race to the Maven job
- prepare next development version 5.0.34
- bump version to 4.0.56
- prepare for next development iteration 4.0.57-SNAPSHOT
- guardrails + OBO + cost + run-registry AI bean parity with SB4
- config-driven AI routing parity with the SB4 starter
- install governance decision log out-of-box for the queryable audit trail
- warn on unauthenticated A2A endpoint + advertise declared security scheme
- make spring-boot-agui-chat a real AG-UI agent via the native bridge @Agent + @Prompt + real @AiTool through session.stream() (demo fallback when no key); AiEvent->AgUiEvent over /atmosphere/agent/{name}/agui; replaces the scripted controller
- config-driven cost/latency/model routing rules in atmosphere.ai.routing extends F3a (content-only); compose order content->model->cost->latency; off-by-default + content behavior byte-identical
- emit experimental OTel GenAI semconv span attributes via GenAiTracer gen_ai.usage./request+response.model/operation/provider on the live span; fixes provider Runtime-Truth bug (real runtime name, not hardcoded atmosphere); legacy ai.tokens. byte-identical
- add --routing flag to 'atmosphere new' for routing config scaffolding injects a commented atmosphere.ai.routing.* block into AI-template application.yml; off by default, rejected for non-AI templates
- wire real LongTermMemory cross-session recall into personal-assistant InMemoryLongTermMemory + LongTermMemoryInterceptor on the UpstreamMcpAgent @AiEndpoint (no-arg interceptor + static holder pattern); makes the memory-bearing claim true
- opt-in RoutingLlmClient via atmosphere.ai.routing.enabled autoconfig wraps the resolved client with content-based routing rules; adds AiConfig.installClient seam; default-off byte-identical
- wire ApiKeyResolver into anthropic/cohere with provider env-var support renamed from CredentialResolver (clashed with AiGateway.CredentialResolver); per-provider precedence reads ANTHROPIC_API_KEY/COHERE_API_KEY, no cross-provider key leak
- add generation params (temperature/maxTokens/topP/stop) to LlmSettings wired to the wire for built-in/anthropic/spring-ai/langchain4j; honest per-runtime matrix in README; empty=byte-identical
- explicit prompt-cache-key tri-state replaces base-URL sniffing PromptCacheKeyMode AUTO/ENABLED/DISABLED on LlmSettings; AUTO preserves current per-path heuristics byte-for-byte
- store resolved apiKey on LlmSettings so apiKey() works for any client removes the OpenAiCompatibleClient-only instanceof; 4-arg constructor preserves old behavior; adds CredentialResolver precedence primitive
- provider-neutral model tier aliases (fast/frontier/reasoning) ModelTier resolves tier tokens to a concrete model by active provider; raw model strings pass through unchanged
- add provider-neutral configureNativeClient(Object) to AbstractAgentRuntime type-checked against nativeClientClassName(); provider-typed static setters remain the primary wiring path
- reachable agent bridge + keep response open during AG-UI streaming AgUiAgentBridge made public (cross-module reflective invoke from agui handler); handlePost joins the run thread so virtual-thread SSE writes don't hit a recycled response — fixes the agui-chat demo+UI e2e (only RUN_STARTED was reaching the wire)
- converge AUTO prompt-cache-key to one default-deny allow-list built-in and framework runtimes share CacheHint.endpointAcceptsPromptCacheKey; framework no longer emits on unknown hosts under AUTO (force via PromptCacheKeyMode.ENABLED)
- honor per-request ToolLoopPolicy in anthropic/cohere/langchain4j tool loops they hardcoded a 5-round cap and ignored maxIterations/onMaxIterations; now route through the shared ToolLoopGuard like the built-in (default behavior unchanged)
- make default model configurable, default claude-sonnet-4-6 adds anthropic.model system property; per-request and AiConfig models still win over the fallback
- version-bump touches only Atmosphere deps; regen SKILLCARDs
- repair rag-chat/mcp-server/browser-agent + SB3 Tomcat + stream errors
- restore real third-party dep versions clobbered by 4.0.x bump
- pin deny-policy refusal on A2A and AG-UI bridges
- fail-closed Maven Central pre-check guards against version burn
- e2e proving config-driven routing is consumed on the wire
- attribute GenAI "experimental" to the OpenTelemetry spec, not the emitter GenAiTracer/MetricsCapturingSession Javadoc + README make clear the implementation is production code; only the upstream OTel GenAI convention is experimental
- document atmosphere new --routing flag and correct agui-chat sample row agui-chat is now a real @Agent (LLM + @AiTool over the AG-UI native bridge), not scripted
- consolidate per-model-call observability into ModelCallScope replaces duplicated fireModelStart/End/Error + timing across 9 adapters and 2 Kotlin runtimes; event count/ordering unchanged (ADK start-time aligned to dispatch)
- unify tool-call accumulator across built-in, anthropic, cohere shared ToolCallAccumulator gains argumentsAsMap(); deletes the two private copies; built-in parse path unchanged
- extract AbstractSseLlmClient shared by Anthropic and Cohere clients collapses ~268 lines of duplicated HTTP/SSE plumbing (header filter, snippet read, data: loop, tool-schema) into one base; wire behavior byte-identical (black-box suites unchanged)
- add TokenUsage.fromCounts and migrate adapter usage translation collapses 11 hand-rolled null-guard/total-fallback sites; 2 sites now compute total=input+output instead of 0 when the provider omits total (regression-tested)
- hoist models() default into AbstractAgentRuntime removes 9 byte-identical adapter overrides; koog (distinct logic) and the interface default unchanged
- fix cancel-test race by awaiting worker interrupt observation worker records the interrupt asynchronously; wait on a latch instead of reading the flag right after whenDone()
- correct AI doc/sample drift vs verified runtime capabilities embeddings 5->7 runtimes, TOOL_CALL_DELTA Built-in+Cohere, ai.md classpath table, agui relabel, samples.json reattach
- bound playwright install with timeout to prevent multi-hour hangs
- both-layer regressions for the sweep failures (JUnit + Playwright)
- sync version stamp to 4.0.56-SNAPSHOT
- deep-link concept tables to docs site; fix verifier count
- bump version to 4.0.55
- prepare next development version 5.0.33
- prepare for next development iteration 4.0.56-SNAPSHOT
- Static verifier over MCP. The plan-and-verify ("Guardians") stack is
reachable as read-only MCP tools when
atmosphere-verifieris on the classpath:atmosphere_verifier_summary,atmosphere_verifier_examples, andatmosphere_verifier_check. The check tool plans a goal and runs every verifier over the resulting plan without executing it (statusverified/refusedwith the per-verifier violations); the mutating verify-then-execute path stays behind the admin write gate.
- wasync: a user
close()is no longer resurrected by a late OPEN event — a close requested before the transport finished opening is now honored when the OPEN arrives, instead of reviving the connection. - Documentation accuracy sweep — corrected the Z3 binding version (4.14.0)
and
SmtCheckerpriority (200); aligned ADK / Semantic Kernel / Alibaba versions, crewai test counts, and the ms-governance policy name; fixed the embedded-jetty client type, the admin-bundle default authorizer, and runtime-truth claims in the embabel / agentscope / coding-agent docs; corrected third-party dependency versions and citations.
- CI doc-drift gates — fact/enumeration checks, link-rot detection, and
sibling-site (atmosphere.github.io) verification, plus an
atmosphere-skillslink-checker allowlist.
- Rich human-in-the-loop approval payloads. A reviewer can now resolve a tool
approval with more than approve/deny: approve-with-edited-arguments (the
tool runs with the reviewer's arguments) or respond (the reviewer answers on
the tool's behalf — structured JSON or free-form text — and the tool does not
run). Wire protocol:
/__approval/<id>/approve {"arguments":{…}}and/__approval/<id>/respond {…}. Fail-safe: a malformed edited-args payload denies. Session-scoped in-memory (not crash-durable). The legacy boolean resolution path is unchanged. - Eval flywheel.
JournalDatasetPromoterturns a recordedCoordinationJournalinteraction into anEvalCasedataset row (trace→dataset), andSampledLiveScorergrades a configurable fraction of live turns intoEvalRunverdicts (online scoring). Both are wired intoEvalControllerwith admin REST routes (/api/admin/evals/dataset,/dataset/promote,/score). - OAuth on-behalf-of credential vault.
OAuthOnBehalfOfCredentialStoreis a concreteCredentialStorethat performs an RFC 8693 token exchange — swapping a user's stored subject token for a short-lived access token scoped to a downstream tool, so an agent calls external APIs as the user. Fail-closed (no token → no fallback credential), token-cached until expiry. Opt in withatmosphere.ai.identity.oauth-obo.enabled=true. - Realtime voice bridge.
VoiceBridge+ theRealtimeVoiceProviderSPI bridge client audio frames over the existing WebSocket broadcaster to a speech-to-speech provider, fanning synthesized audio (Content.Audio) and transcripts back to the client. A dependency-freeLoopbackVoiceProviderships as the runnable reference (echoes audio); OpenAI Realtime / Gemini Live providers implement the same SPI. - Content-safety moderation guardrail.
ModerationGuardrailblocks turns whose request and/or response is flagged for hate / harassment / self-harm / sexual / violence / illicit content, on the existing fail-closed guardrail pipeline. Pluggable detector: zero-depRuleBasedModerationDetector(default) or cross-runtimeLlmModerationDetector. Fail-closed by default (a detector outage blocks the turn;.failOpen()is the explicit opt-out). Opt in withatmosphere.ai.guardrails.moderation.enabled=true(...detector=llmfor the model tier). - Self-healing structured output.
@AiEndpoint(structuredOutputRetries = N)(or theai.structured.retryrequest-metadata key on theAiPipelinepath) re-prompts the model with the schema-validation error as feedback when a typed response fails to parse, up toNextra attempts, then fails closed. Works identically on the websocket and channel-bridge paths. - OpenAPI → governed tools.
OpenApiToolImporterturns an OpenAPI 3.x spec (JSON or YAML, with local$refresolution) intoToolDefinitions whose executor performs the HTTP call. The imported operations ride the same policy-admission and plan-and-verify path as hand-written@AiToolmethods;approvalForWritesroutes mutating verbs through the HITL gate. - MCP client depth.
McpClientOptionsadds per-server tool filtering and display-only renaming (the executor still calls the server's original tool name), plus elicitation/sampling callback handlers advertised duringinitialize.McpServerRegistryaggregates several servers into one collision-free tool list (first-wins) and owns their lifecycle.
- MCP authorization now validates bearer tokens end-to-end. A request is authenticated
when either a servlet resource-server filter set the request principal (e.g. Spring
Security
oauth2ResourceServer) or a configuredTokenValidatoraccepts theAuthorization: Bearertoken (loaded fromorg.atmosphere.auth.tokenValidator, validated byatmosphere-mcpitself — no framework-specific wiring). The RFC 9728 metadata is now served on the agent registration path too. Proven end-to-end on the embedded server, Spring Boot, and Quarkus (JVM). Thespring-boot-mcp-serversample gains an opt-inauthprofile (default off) demonstrating it. - MCP runs on Quarkus.
@Agent-based MCP endpoints now register under the Quarkus extension (the build scan recognizes@Agentand indexes the optionalatmosphere-agent/atmosphere-mcpjars when an@Agentclass is present). JVM mode; native image is not yet supported for@Agent-based MCP.
- Added a stateless
2026-07-28round-robin end-to-end test (twotools/callwith no session header both succeed, plusserver/discoverandMcp-Methodmismatch) inmodules/integration-tests, proving the no-session-affinity claim over live HTTP.
- MCP
2026-07-28release candidate — the largest MCP revision since launch, implemented as a stateless dialect that coexists with the session-based protocol (2024-11-05through2025-11-25). The dialect is selected per request (the client carries the protocol version inparams._metaor callsserver/discover), so existing clients are unaffected. Stateless core has noMcp-Session-Idand noinitializehandshake, so the server runs behind a plain round-robin load balancer with no session affinity. - MCP operability —
Mcp-Method/Mcp-Namerouting headers (validated against the body),ttlMs+cacheScopecache metadata ontools/list/resources/list/resources/read, and W3C Trace Context (traceparent/tracestate/baggage) read from_metaand bridged into the OpenTelemetry span. - MCP Tasks extension (
io.modelcontextprotocol/tasks) and multi-round-trip input —@McpTool(longRunning = true)returns a task handle polled viatasks/get, and the stateless dialect can returnInputRequiredResultwith a base64requestStateto request more input mid-call and resume on any instance. - JSON Schema 2020-12 dialect (
$schema) on generated tool input schemas, and a standardized resource-not-found error (-32602) on the stateless dialect. - MCP Apps (SEP-1865) —
@McpTool(uiResource = "ui://…")plus atext/html;profile=mcp-appresource makes a tool an MCP App. The Atmosphere console is a working host: it renders the app in a sandboxed iframe, runs a bidirectional App Bridge (apps call server tools through the host under the policy gateway; the host lists and calls the app's ownappCapabilities.tools), and uses a separate-origin sandbox proxy for isolation (atmosphere.mcp-sandbox-origin, with alocalhost↔127.0.0.1dev fallback, otherwise an opaque-origin direct sandbox). - MCP authorization (protocol glue) — the server acts as an OAuth 2.0 Resource Server:
RFC 9728 protected-resource metadata at
/.well-known/oauth-protected-resourceand a401+WWW-Authenticatechallenge for unauthenticated requests; opt in via theorg.atmosphere.mcp.auth.*init parameters. This release shipped the protocol glue only; bearer-token validation was wired end-to-end in 4.0.52 (see Unreleased).
- Pruned dead/unwired internal classes found during a release-readiness audit —
none was documented, advertised, or reachable from a user code path:
McpWebSocketHandler(superseded byMcpHandler's direct WebSocket-frame handling),AgUiSession(superseded byResourceAgUiStreamingSession),AiCoalescingBroadcasterCache(a delegate-onlyBroadcasterCachethat the no-arg reflective cache-wiring path cannot instantiate),AdkArtifactBridge,AdkCompactionBridge,AtmosphereRequestBridge,AtmosphereResponseBridge, the channelsAuditLoggingFilter(never registered as a bean, so it never reached the filter chain), the unwiredGrpcProtocolBridge, and the A2AListTaskPushNotificationConfigsResponseDTO (theListTaskPushNotificationConfigsmethod returnsERROR_PUSH_NOT_SUPPORTED, so the response type was never constructed).
ToolBridgeUtils.findUnescapedQuoteno longer advances the scan index past the end of the string when malformed tool-call JSON ends in a lone backslash — the escaped-character skip is now bounds-checked (boundary safety, Correctness Invariant #4). Regression test added.
-
Interactions API (
org.atmosphere.interactions, artifactatmosphere-interactions) — a stateful agent-turn resource layered above theAgentRuntimeSPI, so it works for every adapter with no per-runtime code. AnInteractioncarries a stable id, a durablesteps[]event log, and chains turns viapreviousInteractionId(the server holds history; the client does not resend it). Turns run synchronously or in the background (background=truereturns aRUNNINGrecord immediately and is retrievable after a disconnect), andstore=falsestreams without persisting. The starter exposes the resource overPOST /api/interactions,POST /api/interactions/{id}/continue,GET /api/interactions/{id},GET /api/interactions,POST /api/interactions/{id}/cancel, andDELETE /api/interactions/{id}— every mutating route is default-deny behindatmosphere.interactions.http-write-enabledplus an authenticated principal (Correctness Invariant #6). TwoInteractionStorebackends ship:InMemoryInteractionStore(default) andSqliteInteractionStore; the SPI is pluggable for others.atmosphere.jsgains a typedInteractionsClient(atmosphere.js/interactions) covering the REST surface pluspollUntilTerminal/watchhelpers. -
Interactions live streaming — a background interaction now streams its durable
steps[]to a subscribed browser as they are produced, over the Atmosphere transport (/atmosphere/interactions-stream?id=<id>, WebSocket/SSE). On connect the handler replays the steps captured so far (late-joiner catch-up, deduped client-side by sequence), then pushes each new step live and a terminal frame on completion; ownership is enforced per-interaction, same scope as the REST read.InteractionsClient.subscribe(id, handlers)bridges it on the client and the Atmosphere Console's Interactions tab renders the live step timeline. AnAtmosphereInterceptorresolves the principal for the stream socket so ownership holds across all transports (a servlet filter's request attribute does not survive the WebSocket upgrade). Demonstrated inspring-boot-coding-agentandspring-boot-multi-agent-startup-team. -
ToolKind+@AiTool(kind = …)— tools declare a behavioural category (EDIT,READ,EXECUTE,NETWORK,DELETE,OTHER; defaultOTHER). This makesPermissionMode.ACCEPT_EDITSa real behaviour instead of aDEFAULTalias: it now auto-approves a tool's own@RequiresApprovalprompt whenkind == EDIT, while every other tool still routes through the per-tool approval gate. The classification is compile-time author metadata (not runtime caller-asserted intent), the defaultOTHERkeeps the approval posture exactly as restrictive as before, and the relaxation never overrides an operator-configuredToolPermissionPolicyDENY/CONFIRMor aDenyAllpolicy.ToolExecutionHelperAcceptEditsTestpins all four cases. -
Code-as-action sandbox (
org.atmosphere.ai.code) — acode_exectool that lets a model accomplish tasks by writing a block of code (bash / JavaScript / Python) instead of negotiating many fine-grained tool calls. Each session gets an isolated, ephemeral container (CodeSandboxSPI,ContainerCodeSandboxover Docker/Podman) with hardening applied —--network noneby default, non-root,--cap-drop ALL,--security-opt no-new-privileges, read-only rootfs + a bounded writable workspace, and memory/cpu/pid caps — provisioned lazily on first use and torn down on every terminal path via the newStreamingSession.onTerminate(AutoCloseable)primitive. Default-deny: code execution is off unlessorg.atmosphere.ai.code.enabled=trueand a container engine is confirmed present at runtime (Correctness Invariant #5); the tool is registered into@AiEndpointdispatch only then, with the tool-loop ceiling lifted to 25 write→run→observe rounds. Each round streams anAiEvent.AgentStepplus any screenshots the code produced, rendered inline in the Console as markdown data-URI images. Newsamples/spring-boot-browser-agentdemonstrates it (Cohere-backed, requires Docker): the agent drives a headless browser with Playwright and you watch the screenshots arrive live.
ai-policy-regoandai-policy-cedarnow ship aMETA-INF/services/org.atmosphere.ai.governance.PolicyParserregistration, so Rego and Cedar policy artifacts are auto-discovered byServiceLoaderthe same way YAML always has been — no programmatic parser wiring required. Safe because both parsers have lazy no-arg constructors (theopa/cedarbinary is only touched at evaluation, and parse failure is already fail-closed). The Kafka/Postgres audit sinks are deliberately left on programmaticGovernanceDecisionLog.addSink()wiring: they need a live broker / JDBC connection, so auto-activating them on classpath presence would advertise capability that cannot run (Runtime-Truth, Correctness Invariant #5).RegoPolicyParserTest/CedarPolicyParserTestpin the discovery.- Four new pre-push drift-prevention gates, each closing a class the
.harness/drift-log.mdhad recorded but left un-automated, wired intoscripts/pre-push-validate.shTier-1:validate-runtime-overlay-coverage.sh(every snapshot runtime must have a CLI overlay and abom/pom.xmlartifact — drift #59);validate-dangling-doc-comments.sh(parse-onlyjavac -Xlint:dangling-doc-commentsunder a JDK ≥ 23 to catch detached Javadoc locally, not only on the Native Image lane — drift #80);validate-doc-version-alignment.sh(third-party dependency versions in Markdown must match the pinnedpom.xml/package.json— drift #12/#18/#75); andvalidate-doc-symbols.sh(annotation references in Markdown must resolve to an in-tree declaration or a curated external allowlist — drift #72). Two of the gates caught a pre-existing drift on first run:atmosphere-semantic-kernelwas missing frombom/pom.xml(now added), andmodules/langchain4j/README.mdnamed LangChain4j 1.12.2 while the pom pins 1.15.0 (now corrected). CLI overlay coverage was also extended to the three native runtimes (anthropic,cohere,crewai) incli-e2e.ymlpath filters and thetest-cli.shscaffold+compile matrix.
-
atmosphere-crewai—AgentRuntimefor the CrewAI multi-agent framework via an out-of-process Python sidecar. First non-Java runtime adapter in the project; the boundary isHTTP + SSEfor the request stream plus a loopbackToolCallbackServerfor Java→Python tool RPC. Pins 9 capabilities (TEXT_STREAMING,TOKEN_USAGE,AGENT_ORCHESTRATION,CANCELLATION,TOOL_CALLING,SYSTEM_PROMPT,STRUCTURED_OUTPUT,TOOL_APPROVAL,PER_REQUEST_RETRY) viaCrewAiRuntimeContractTest+ the capability snapshot (which now enumerates 12 runtimes). Like every other runtime,isAvailable()is config-gated — requiresATMOSPHERE_CREWAI_SIDECAR_URLpointing at a running sidecar that responds OK toGET /health. -
modules/crewai/sidecar/— companion Python packageatmosphere-crewai-bridge(FastAPI + uvicorn + crewai 1.14) speaking the documented wire protocol. Materialises JavaToolDefinitions ascrewai.tools.BaseToolsubclasses viapydantic.create_model, injects them into agents, and threadscontext.systemPrompt()into each agent'sbackstoryinside a delimited block. Ships with a workingexamples/ollama_crew.pyfactory that targetsqwen2.5:0.5b(no API key required). -
CLI runtime overlay (
cli/runtime-overlays.json) forcrewai, soatmosphere new my-app --template ai-chat --runtime crewaiscaffolds with the dependency wired and the sidecar setup documented inline. -
End-to-end validation captured at
.harness/crewai-e2e-success.png: chrome-devtools drove/atmosphere/console/against a real Ollama-backed crew; the browser rendered 25 tokens at 46.8 tok/s through the full chainWebSocket → @AiEndpoint(runtime=crewai) → HttpSseSidecarClient → atmosphere-crewai-bridge → crewai 1.14 → litellm → Ollama. Console zero errors, sidecar log confirmsPOST /v1/chat/completions HTTP/1.1 200 OKagainst the local Ollama instance. -
modules/coordinator/journal— event-sourced execution log for the coordinator. Layers four additive pieces onto the existingCoordinationJournalSPI without breaking any of the 119 existingnew CoordinationEvent.*call sites across coordinator / admin / checkpoint / integration-tests:EventEnvelope(eventId, parentEventId, event)+ default-methodrecordEnveloped/retrieveEnvelopedonCoordinationJournal.JournalingAgentFleetthreads parent IDs through every dispatch path (parallel/pipeline/route/proxy.call/callAsync/stream):CoordinationStarted→AgentDispatched→AgentCompleted/AgentFailed→AgentEvaluated. Legacyrecord(event)callers continue working — events are wrapped as root envelopes with no parent.CoordinationProjection.from(journal, coordinationId)— pure read-only causal DAG built fromretrieveEnveloped. Exposesroots(),children(eventId),walk(visitor),agents(),failedDispatches(),evaluations(). No execution, no LLM, no side effects.FileCoordinationJournal(Path)— append-only NDJSON file backend, one JSON object per line. Replays onstart()into an in-memory index for queries; tolerates a truncated final line from a JVM kill mid-append (logs and skips). Single-writer locked appends; polymorphic ser/deser of the sealedCoordinationEventhierarchy via a Jackson 3 mix-in so the event records stay annotation-free.CoordinationFork+ newForkCreatedevent variant — what-if branching primitive.fork.from(coordId, eventId).reason(...).with(altCall).execute(fleet)creates a new coordination id (or accepts an explicit one), records aForkCreatedenvelope linking back to the parent event, and runs the alternate dispatch viaJournalingAgentFleet.withCoordinationId(...). The parent coordination is immutable; the fork is a peer with its own future. Pre-flight check rejects unknownparentEventIdwith a fastIllegalArgumentException.
Backed by 78 tests in
modules/coordinator/src/test/java/.../journal/including a three-process integration test that runs a parallel coordination, restart-replays from disk, projects the DAG, forks an alternate, restart-replays again, and verifies both the original and the forked branch survive across two simulated JVM kills.modules/coordinator/README.mddocuments the new surface. -
Cohere
TOOL_CALL_DELTAstreaming capability (3327425d50).CohereChatClient.handleToolCallDeltasurfaces incremental tool-call argument fragments as they arrive, andCohereAgentRuntime(line 269) now declaresTOOL_CALL_DELTA. The same honesty pass removedPROMPT_CACHINGfrom Cohere — the v2 API exposes no prompt-cache control, so advertising it was Runtime-Truth drift; the capability snapshot was re-pinned accordingly. -
Quarkus extension integration parity: five optional surfaces, each gated on classpath presence and covered by a dedicated build-step test (
3327425d50).AtmosphereProcessorregisters Cache, Health (HealthBuildItem), Micrometer metrics (AtmosphereMetricsProducer), OpenTelemetry tracing (AtmosphereTracingProducer), and governance metrics (AtmosphereGovernanceMetricsProducer) producers — seeAtmosphereProcessor.java:432-510and theAtmosphere{Cache,Health,Metrics,Tracing,GovernanceMetrics}BuildStepTestsuite. -
modules/quarkus-grpc— Quarkus gRPC bridge extension (runtime+deploymentsubmodules) (3327425d50). -
scripts/validate-no-beta-on-main.sh— push-time gate enforcing the release-frequency rule: pre-GA escape-hatch framing (beta annotations, hourglass deferral markers, phased planning labels, or roadmap-deferral prose) introduced relative toorigin/mainfails the build, somainstays release-ready (3327425d50).
- Bumped JetBrains Koog
0.8.0 → 1.0.0(4685a844bb, root pomkoog.version) — Koog's first GA. The adapter configures via Koog 1.0's stableOpenAILLMClient/MultiLLMPromptExecutor(AtmosphereKoogAutoConfiguration.kt); the full Koog capability set (VISION,AUDIO,MULTI_MODAL,PROMPT_CACHING,TOOL_CALLING,TOOL_APPROVAL, …) is unchanged and re-pinned byKoogRuntimeContractTest+ the capability snapshot. - Bumped
langchain4j.version1.14.0 → 1.15.0(abd774f68d),logback-version1.5.25 → 1.5.32(58f2e6d373), andcommons-lang33.18.0 → 3.20.0(8dea5788ac).
HttpSseSidecarClientnow pinsHttpClient.Version.HTTP_1_1. The JDK'sjava.net.http.HttpClientdefaults to HTTP/2 for plain HTTP and attempts anUpgrade: h2cnegotiation; uvicorn (the FastAPI host for the CrewAI sidecar) does not implement the h2c upgrade and the resulting request lands with an empty body, which FastAPI rejects as422 Field required, loc=["body"], input=null. The bridge-testFakeSidecar(acom.sun.net.httpserver.HttpServer) tolerated the upgrade preamble and parsed the body anyway, so the bug only surfaced under real uvicorn — exactly the gapfeedback_chrome_devtools_only.mdwarns about. Added a regression test (CrewAiAgentRuntimeBridgeTest.httpClient_pinnedToHttp11) that reflects into the client and asserts the version, so a future "just use the defaultHttpClient" refactor breaks the build before it breaks production. Drift recorded as.harness/drift-log.md#64.- Koog runtime reaches Gemini via Google's OpenAI-compatible base
URL (
87aa2cc824). Koog 1.0's native Google client ships only on a JVM-incompatible path, soAtmosphereKoogAutoConfigurationpoints the stableOpenAILLMClientat any OpenAI-compatible endpoint whenatmosphere.koog.base-url/LLM_BASE_URLis set (e.g.https://generativelanguage.googleapis.com/v1beta/openaiforgemini-2.5-flash). Regression-gated byAtmosphereKoogAutoConfigurationTest. Drift recorded as.harness/drift-log.md#77 — the0.8.0 → 1.0.0bump had been reported done on CI alone, which hid the dropped-Gemini regression. - Spring Boot JDK 26 long-term-memory disconnect hang resolved via
an idle-reaper fallback (
b2e9e09e71).LongTermMemoryHttpE2eTest's disconnect path intermittently hung on the JDK 26 lane because the WebSocket-close →onDisconnectlifecycle could be dropped under fork contention; anIdleResourceInterceptor-based reaper (platform-thread scheduler,maxInactiveActivity=5000) now fires the disconnect lifecycle independently, so suspended resources are reaped and facts persisted even when the close frame is lost. Drift recorded as.harness/drift-log.md#78–#79 — an earlier 60s → 120s await bump was ineffective (a timeout cannot fix a hang).
- Bumped
tomcat-embed-core11.0.21 → 11.0.22(root pomtomcat-versionproperty) to close 7 Dependabot advisories — 3 critical (security-constraint bypassGHSA-5m62-pw8w-7w9f, digest-auth bypassGHSA-h6fc-48rj-7qqh, HTTP/2 header validationGHSA-r29c-68gh-xp6x), 3 high (LockOutRealm case-sensitivityGHSA-5mp6-jrq3-r938, WebSocket auth-header exposureGHSA-fv25-8xcx-gqjc, WebDAVLOCK/PROPFINDunbounded readGHSA-gx5v-xp9w-j4cg), and 1 low (AJP secret non-constant-time compareGHSA-9m89-8frq-c98c). The pin stays scoped totomcat-embed-core;tomcat-embed-elandtomcat-embed-websocketcontinue to follow each Spring Boot BOM (3.5.x keeps the 10.1.x line, 4.0.x stays on 11.0.x). - Bumped
protobufjs7.5.6 → 7.5.8inmodules/integration-tests/package.json+ lockfile to closeGHSA-jggg-4jg4-v7c6. - Dismissed 3 remaining open Dependabot alerts that have no in-tree
fix path. Two
org.json:jsonalerts (GHSA-3vqj-43w4-2q58,GHSA-4jq9-2xhw-jpx7) citedmodules/runtime/pom.xml— a manifest that no longer exists;org.json:jsonwas removed reactor-wide in commit4f40968d4d(4.0.42-SNAPSHOT, "drop org.json:json — Jackson 3 only"). Dismissed asnot_used. Oneopentelemetry-apialert (GHSA-rcgg-9c38-7xpx/CVE-2026-45292, medium DoS via unbounded W3C Baggage Propagation) is blocked upstream: Quarkus 3.35.x and 3.36.0 both ship OTel1.60.1, and thesamples/quarkus-ai-chatpin must follow the BOM to keepquarkus-micrometer-registry-prometheusworking. Dismissed astolerable_risk(sample, baggage propagation not enabled, Vert.x enforces the 8 KiB header limit recommended in the advisory). Re-evaluate when Quarkus's BOM picks up OTel 1.62+.
- CLI runtime overlays for
anthropicandcohere(cli/runtime-overlays.json). Both runtimes had been shipped inmodules/and documented in the top-level README —atmosphere-anthropicsince 2026-05-19 (1195845304),atmosphere-coheresince 2026-05-23 (1dfebcb5ff) — but neither had a CLI scaffolding overlay. The commandatmosphere new my-app --template ai-chat --runtime cohere(or--runtime anthropic) now works. Same change adds both artifacts tobom/pom.xmland the parentpom.xml's<dependencyManagement>so a Maven build resolves their version without an explicit<version>in the consuming pom. Verified end-to-end via chrome-devtools against the Atmosphere Console: real Coherecommand-a-plus-05-2026LLM response over WebSocket with 18.3 tok/s streaming through theCohereChatClient→ realhttps://api.cohere.com/v2/chatHTTP call. - Durable hibernating
Workflow<S>primitive inatmosphere-checkpoint(a0ac15f1e3). OrdersWorkflowStep<S>instances over an application-owned state type and composes the existingCheckpointStoreSPI for persistence. SealedStepOutcome<S>(Advance/Hibernate/Done/Fail) andWorkflowResult<S>(Completed/Hibernated/Failed) drive the runner; per-stepmaxRetries()+retryDelay()cover transient failures. Hibernation is return-not-park: a step that returnsStepOutcome.hibernate(state)writes a snapshot and the call returns to the caller with no platform thread held; a laterrun()against the same coordination resumes at the next un-completed step, including across JVM restarts when the store is persistent.WorkflowSqliteResumeTestpins the cold-restart contract — closesSqliteCheckpointStore, opens a fresh handle on the same file, builds a freshWorkflowinstance, and asserts only the un-completed step executes. Ten unit tests cover linear execution, hibernate-and-resume, retry-success, retry-exhaustion, explicit fail, duplicate-step-name rejection, snapshot-precedence overinitialState, anddeleteAllSnapshots. SqliteLongTermMemoryandRedisLongTermMemory(835a88d252, rebased tofbbfa457a2) — persistent backends for theLongTermMemorySPI inatmosphere-durable-sessions-sqliteandatmosphere-durable-sessions-redis. Both can share a connection with their siblingSessionStore/ConversationPersistenceimplementations.LongTermMemoryBackendIntegrationTestparameterizes the fullLongTermMemoryInterceptorround-trip over all three backends;LongTermMemoryMultiInstanceTest(d4609cf0fc) proves the pod-A-writes / pod-B-reads scenario the persistent backends exist for, using two independentLongTermMemoryhandles against the same shared store.scripts/validate-backend-class-refs.sh(835a88d252) — structural gate scanning*.javaJavadoc and*.mddocumentation for(Sqlite|Redis|Postgres|Mongo|Cassandra|Hazelcast|JGroups|Kafka|Nats)<Word>tokens that don't resolve to a declared class inmodules/**/src/{main,test}/java/..harness/external-class-allowlist.txtwhitelists genuine third-party types (Lettuce, Kafka, Testcontainers, brand names). Wired intopre-push-validate.shTier-1. Catches future SPI-backend overclaim drift before it merges (the class of bug that drift #53 logged on the originalLongTermMemoryJavadoc).- Per-runtime
SKILLCARD.yamlmanifests with OpenSSF Model Signing (32a8e8b935+ this commit) — capability + provenance documents that are signable via the same Sigstore-keyless toolchain NVIDIA's verified-agent-skills programme uses. Cards ship unsigned (signing.status: unsigned); signatures are produced at release-tag time by.github/workflows/sign-skillcards.yml.scripts/regen-skillcards.shemits one card per snapshot-pinned runtime atmodules/<X>/SKILLCARD.yaml, derived from.harness/capabilities.snapshot.jsonand each module'spom.xml. The repo-rootSKILLCARDS.mdcatalog (regenerated by the same script) lists every shipped runtime, its capability count, and its signature state — that file is the source of truth for "which runtimes have a card", not this paragraph (a named list and count would stale every time a new adapter lands). Each card declaresspec: atmosphere/skillcard/v1with artifact coordinates, the registeredAgentRuntimeSPI implementation FQN, the alphabetical+count-pinnedAiCapabilityset, contract-test path, license (Apache-2.0), and asigningblock referencingsignature_file: SKILLCARD.yaml.sigwithenvelope: openssf-model-signing/v1andbundle_format: sigstore..github/workflows/sign-skillcards.ymlsigns every card on tag push viamodel_signing sign sigstore— short-lived Fulcio cert- Rekor transparency-log entry, OIDC identity bound to the
workflow path — and uploads the
.sigfiles as a GitHub release asset and as a workflow artifact for downstream bundling. Cards AND signatures are bundled into each runtime jar atMETA-INF/atmosphere/via a root-pom<resource>declaration so consumers can verify integrity without unpacking the source tree; modules without a SKILLCARD (cpr, mcp, channels…) see the include filter match nothing and are unaffected.SkillCardSnapshotTestinatmosphere-ai-testenforces three contracts: (a) capability set + count drift against the snapshot, (b) every snapshot runtime has a card on disk, (c) shape conformance with required top-level keys (schema_version,spec,status,name,language,description,license,artifact,spi,capabilities,contract_test,provenance,signing) and required signing fields (envelope,signature_file). When a.sigis present beside a card, the test shells out tomodel_signing verify sigstorewith the Atmosphere workflow's identity pin and fails on any signature mismatch; sigs are skipped silently when absent (the normal state onmainbetween tagged releases) or when themodel_signingCLI is not installed locally.scripts/scan-skillcards.shis the SkillSpector-equivalent pre-publish gate — scans every card for prompt-injection markers (regex set: "ignore previous instructions",[INST], ChatML role tags), hidden Unicode (zero-width chars, Bidi overrides), capability-safety violations (TOOL_CALLING ⇒ TOOL_APPROVAL per OWASP excessive-agency), missing SPI classes (FQN doesn't resolve to a source file on disk), and path-shaped-field safety. HIGH-severity findings fail pre-push and the signing workflow, so a compromised manifest can never be published as "signed".scripts/validate-capability-claims.shruns all three ofregen-skillcards.sh --check,scan-skillcards.sh --check, and the snapshot freshness check;scripts/sign-skillcards.sh+verify-skillcards.share the local CLI wrappers (key / certificate / sigstore modes).regen-skillcards.shadditionally emitsSKILLCARDS.mdat the repo root — the catalog index that lists every runtime, its signature state, and links to the card + contract test. Distribution model: git itself is the daily sync, consistent with the rest of this repository; release-time signatures are also attached to the GitHub release as workflow artifacts. Pre-push validator regex coversSKILLCARD.yaml(.sig)?,(regen|sign|verify|scan)-skillcards.sh, the signing workflow, andSKILLCARDS.md. Curated runtime-specific risk and mitigation prose remains in each runtime's module README.
- Rekor transparency-log entry, OIDC identity bound to the
workflow path — and uploads the
- Native Anthropic Messages API runtime in a new
atmosphere-anthropicmodule (1195845304).AnthropicMessagesClientposts directly tohttps://api.anthropic.com/v1/messages, parses the SSE stream (message_start,content_block_start,content_block_deltawithtext_deltaandinput_json_delta,message_deltacarryingusage.input_tokens/output_tokens,message_stop), and drives thetool_use→tool_resultloop through the sharedToolExecutionHelper.executeWithApproval(max five rounds, cancellation-aware).AnthropicAgentRuntimeis registered viaServiceLoaderat priority 100 — same posture as every other framework runtime — and inheritsexecuteWithOuterRetryso it claimsPER_REQUEST_RETRYhonestly alongsideTEXT_STREAMING,SYSTEM_PROMPT,STRUCTURED_OUTPUT,TOOL_CALLING,TOOL_APPROVAL,TOKEN_USAGE,CONVERSATION_MEMORY,BUDGET_ENFORCEMENT,CONFIDENCE_SCORES, andPASSIVATION.isAvailable()returns true only whenanthropic.api.key(system property orAiConfig.LlmSettings) is present, satisfying Correctness Invariant #5 (Runtime Truth). The capability snapshot, capability matrix, andmodules/ai/README.mdprose were regenerated in the same commit; runtime count is now ten. - LangChain4j 1.15.0 parity (
9e72c6c6f7): tool-error fallback inToolExecutionHelper.executeWithApprovalwraps null/blank exception messages with the throwable's simple class name so NPEs surface as{"error":"NullPointerException"}to the model instead of opaque{"error":"null"}. Custom HTTP headers onOpenAiCompatibleClientcarry proxy / per-tenant / tracing metadata (Helicone, OpenRouter, …); reserved names (Authorization,Content-Type,Accept) are filtered at request-build time.AgentFleet.vote(...)adds consensus dispatch — fans every call out in parallel and returns the result whose normalized text (strip().toLowerCase(Locale.ROOT)) is shared by the most peers, with deterministic insertion-order tie-breaking and a synthetic"vote"failure when every peer fails. - JFR observability, declarative tool permissions, first-run sub-agent
guard, and episodic memory (
63e34f11a4):- JFR events under
org.atmosphere.ai.jfr—AiCallEvent,AgentTurnEvent,ToolInvocationEvent,SubAgentDispatchEvent,EpisodicMemoryAccessEvent,SessionLifecycleEvent,AiErrorEvent— emitted byJfrAiMetrics.CompositeAiMetricslets JFR coexist with Micrometer (and any other backend) instead of one replacing the other. ToolPermissionPolicySPI with thePropertiesToolPermissionPolicyreference impl: declarative ALLOW/DENY rules layered on top of the existing@RequiresApprovalannotation gate. Reachable fromToolExecutionHelperso every runtime inherits it.- First-run sub-agent dispatch guard in
DefaultAgentFleet— the bootstrap pass sequences the first call through every peer individually before the parallel fan-out path is unlocked, so a cold-cache misconfiguration is caught against one peer instead of fanned out N× simultaneously. EpisodicMemoryStoreSPI withInMemoryEpisodicMemoryStoreandJsonFileEpisodicMemoryStorebackends, theMemoryEntry/EpisodicMemoryQuery/EpisodicMemoryTyperecords, and theEpisodicMemoryAccessEventBridgeJFR fan-out.
- JFR events under
GrpcWasyncTransportTeststatus-poll widened from 5 s to 20 s and the@Timeoutfrom 10 s to 30 s for JDK 26 scheduler variance (df19027ab8). Closes a recurring "Core (JDK 21/26)" flake.
samples/spring-boot-coding-agent: case-insensitive README probe (38565e43ef). Repos likesindresorhus/awesomeshipreadme.mdlowercase, which the oldREADME.md-only lookup missed silently. The redundantapplication.propertiesand the unusedatmosphere.ai.runtimesetting were also dropped — the sample is deterministic and never invokes an LLM.
- Spring AI Alibaba: unconditional
TOOL_CALLING/TOOL_APPROVAL/TOKEN_USAGE(534317f03d) —UsageCapturingChatModelwraps the configured Spring AIChatModelbean at auto-configuration time; per-thread accumulator capturesChatResponseMetadata.getUsage()across every step of the ReAct graph and emits a singlesession.usage(TokenUsage)after each dispatch. Tool calling is no longer gated onstaticChatModel != null—SpringAiAlibabaToolBridgeis wired on every dispatch with tools, and the runtime fails fast withconfigurationHint()ifChatModelis missing. Closes the last conditional capability gap from the runtime parity push (62a9b7e6af). - RAG vector-store matrix expanded with three direct connectors
(
31d6455a75):PgVectorContextProvider(Postgres + pgvector via JDBC),QdrantContextProvider(Qdrant REST overjava.net.http.HttpClient), andPineconeContextProvider(Pinecone REST). Each connector embeds the user query throughEmbeddingRuntime, validates caller-controlled identifiers at construction time per Boundary-Safety invariant, and ships with a Mockito-backed unit-test suite.modules/rag/README.mdadds a reachability matrix showing the six direct providers plus the Spring AI / LangChain4j bridges covering the long tail (Weaviate, Milvus, Chroma, Elasticsearch, Redis Stack, MongoDB Atlas, OpenSearch, Cassandra). - Workflow authoring inside the admin control plane (
81ff454177) —WorkflowManifestJSON record,WorkflowStoreSPI withInMemoryWorkflowStoredefault and optimistic-concurrency version conflict detection,WorkflowControllerwithControlAuthorizergating plus audit-log entries on every save / delete, Spring Boot endpoint exposesGET/POST/DELETE /api/admin/workflow, and/atmosphere/admin/workflow.htmlships a vanilla-JS authoring UI that lists / creates / edits manifests against the REST surface. - Eval dashboard inside the admin control plane (
38e2a45920) —EvalRunJSON record,EvalRunStoreSPI with bounded-ring-bufferInMemoryEvalRunStoredefault (500 runs per baseline, oldest-evicted),EvalControlleraggregates pass-rate per baseline, Spring Boot endpoint exposesGET/POST/DELETE /api/admin/evals/{runs,baselines}, and/atmosphere/admin/evals.htmlsurfaces pass-rate meters + recent-run table with auto-refresh. CI submits a JSON body per LLM-as-judge run and the dashboard surfaces the trend without leaving the control plane. atmosphere-admin-bundleenterprise console aggregator (eaad0df089) — single Mavenpom-packaging artifact that transitively pulls inatmosphere-spring-boot-starter,atmosphere-admin,atmosphere-ai,atmosphere-coordinator,atmosphere-agent,atmosphere-rag,atmosphere-checkpoint,atmosphere-durable-sessions, andatmosphere-durable-sessions-sqlite. Adding one dep gives operators the dashboard, journal flow viewer, workflow authoring, eval dashboard, and governance decision viewer; deliberately does not pin anAgentRuntimeadapter or a vector-store driver so operators choose those independently.docs/runtime-selection.md(97130eeeeb) — nine-runtime decision tree walking the questions an architect should answer before picking anAgentRuntime, cross-referenced against the pinned capability snapshot. Companion to the cli / samples "flagship enterprise templates" promotion that calls outrag,ai-tools,guarded-agent,coding-agent, andms-governanceas the canonical agent shapes.
- AI gap Playwright coverage (
e91b8084fd) —ai-gap-coverage.spec.tsexercises the deterministic RAG, input-assembly telemetry, and evaluator artifact paths throughAiFeatureTestServer; Vue, Svelte, and React Native hook tests pin the new chat-hook parity surface. UsageCapturingChatModelTest,SpringAiAlibabaRuntimeContractTest(TC/TA/TU pinned),WorkflowManifestTest,WorkflowControllerTest,EvalControllerTest,PgVectorContextProviderTest,QdrantContextProviderTest,PineconeContextProviderTest(534317f03d,31d6455a75,81ff454177,38e2a45920).
- capability-matrix snapshot + drift gate (
d22d18a7cd) — new.harness/capabilities.snapshot.jsonis the canonical aggregate of theAiCapabilityenum (20 capabilities) and each runtime's pinnedexpectedCapabilities()(9 runtimes). Regenerated byscripts/regen-capability-snapshot.shand validated by bothscripts/validate-capability-claims.sh(wired intoscripts/pre-push-validate.shTier 1) and the newCapabilitySnapshotTestinmodules/ai-test. The per-runtime contract tests already pin per-runtime drift; this layer pins aggregate count claims inmodules/ai/README.mdagainst the snapshot so prose like "All 9 runtimes…" cannot drift from the running code without breaking the build. Adds a "What capability flags do not claim" disclosure block tomodules/ai/README.md§ Adapter Runtimes covering implementation parity, limit numbers, provider-side guarantees, and production fitness — the four edges callers commonly assume from a capability flag and that the flag does not promise. - drift-log + Stop-hook enforcement (
c685f9588f+4f6a51d3a8) — new.harness/drift-log.mdis the append-only record of every agent claim that diverged from ground truth (code, git history, runtime state). Two enforcement points:scripts/validate-drift-log.shchecks structural hygiene (chronological sections, no future dates, prior-section append-only invariant againstorigin/main) and is wired into pre-push Tier 1;.claude/hooks/check-drift-log.shis a Claude Code Stop hook (registered in.claude/settings.json) that greps the session transcript for high-precision drift-correction patterns and blocks session end if the log was not modified. Together with the capability snapshot, this is the verification rail of the harness pattern documented by Anthropic (Effective harnesses for long-running agents) and OpenAI (Harness engineering), applied to AI prose claims about this repo — measuring change failure rate by agent claim, not utilization. Operator notes live in.harness/README.md.
- AiPipeline input-assembly snapshot stale across guardrails+policies (
f16e9da396) — the per-stage telemetry snapshot ofrequest.systemPrompt()was captured before guardrails (AiGuardrail.GuardrailResult.Modify) and governance policies (PolicyDecision.Transform) had a chance to mutate the request. The runtime later executed the post-mutation request, so the system stage was under- or over-reported. Snapshot moved to after both loops have run, before pipeline-driven augmentations (structured-output schema, confidence cue) which are tracked separately. Regression test inAiPipelineInputAssemblyTest. - BudgetCapturingSession wall-clock callback-lazy enforcement (
f16e9da396) — wall-clock cap was sampled only at session-method boundaries, so a provider that hung silently after dispatch never tripped. Now the deadline is scheduled up-front via a daemonScheduledExecutorService; on trip the decorator both routes the typedAiBudgetExceededExceptionthroughsession.errorand fires a pipeline-suppliedonTriphook bound toruntime.executeWithHandle'shandle::cancel, so the in-flight runtime call is cancelled instead of left dangling. The task is cancelled oncomplete()/complete(summary)/error()so the scheduler thread is freed promptly. Existing wall-clock assertion loosened from>to>=(09b2d2b610) because the scheduled task can fire exactly at the deadline. Regression test (wallClockBudgetTripsWhenRuntimeMakesNoSessionCallbacks) covers the no-callback path. - McpToolSource transport leak on initialize/listTools failure (
f16e9da396) —connect(transport, label)constructed anMcpClientand calledinitialize()+listTools()without a failure cleanup path, leaking the underlying transport (subprocess pipes, sockets, HTTP connection pool) for the JVM lifetime if either threw. Wrapped in try/catch withclient.closeGracefully()on failure (Ownership Invariant #1). Regression test stubs anMcpClientTransportwhoseconnect()returnsMono.errorand assertscloseGracefullywas called. - AgentPassivation responseType ignored on resume (
f16e9da396) —AgentSnapshotpersistedresponseTypeNamebutresume()rebuilt the context frombase.responseType(), so a structured-output agent resumed with a base context that lacked the type lost typed parsing despite the snapshot carrying the field. NewresolveResponseTypehelper resolves the snapshot's class name via the thread-context classloader (with fallback tobase.responseType()plus a one-line WARN if the class is not on the resumer's classpath). Regression test inAgentPassivationTest. - off-by-one in
modules/ai/README.md§ ToolLoopPolicy "the other six runtimes" → "the other seven runtimes". With Built-in and Koog handlingCOMPLETE_WITHOUT_TOOLSnatively and 9 runtimes total, the count of "other" runtimes is 7, not 6. Surfaced by the new capability-matrix verification work.
atmosphere.github.iocapability claims aligned with the snapshot. Cross-validated against.harness/capabilities.snapshot.json; fixeddocs/.../reference/ai.mdTOOL_APPROVAL list (Embabel and SK were wrongly excluded),docs/.../tutorial/26-foundation-primitives.mdgateway-consumer count ("seven of nine" → all nine — every runtime callsadmitThroughGateway), added 5 missing capability rows (BUDGET_ENFORCEMENT,CONFIDENCE_SCORES,PASSIVATION,MODEL_ENUMERATION,MULTI_AGENT_HANDOFF) totutorial/11-ai-adapters.md, and refreshed four pre-Koog/SK/AgentScope/Alibaba narrative enumerations to the current 9-runtime set. Website main:13fe8c4..harness/README.md— operator manual for the harness directory (canonical files, validators, hooks, regen + append protocols).
- predictable-AI primitives — three framework-level capabilities that close gaps Bonér's "Herding LLMs" deck flagged for distributed-system reliability, all declared on every framework runtime so the matrix closes without
@Betashims:BUDGET_ENFORCEMENT(a4fae39464) — newAiBudgetvalue record (max input / output / total tokens, max steps, max wall clock) installed viapipeline.setDefaultBudget(...)or per-requestai.budgetmetadata.BudgetCapturingSessiondecorator slots into the AiPipeline session-decorator stack between metrics and guardrail layers; on breach it routes a typedAiBudgetExceededException extends AiExceptionthroughsession.error(...)and short-circuits subsequentsend/usage/progress/emit/completecalls so the wire protocol's "one terminal frame" invariant holds. Distinct fromorg.atmosphere.ai.budget.StreamingTextBudgetManager(long-running per-tenant cumulative spend); this capability is the per-call death-spiral guard. 13 new unit tests cover every breach reason, default vs. per-request override, and the post-trip swallow. Wall-clock limits trip universally; token / step limits depend onTOKEN_USAGE(every runtime except Spring AI Alibaba honors both).CONFIDENCE_SCORES(a4fae39464) — newAiConfidencerecord withOptionalDouble aggregate,List<TokenLogprob>tokens, andSourceenum (LOGPROBS_NATIVE/MODEL_REPORTED_FIELD/HEURISTIC).StreamingSession.confidence(AiConfidence)default method auto-emitsai.confidence.aggregate/.source/.tokensmetadata mirroring theusage(TokenUsage)convention;DelegatingStreamingSessiongains the matching forwarding override. Universal model-reported path via the newAiConfidenceElicitationplus theConfidenceCapturingSessiondecorator: pipeline appends an opt-in cue to the system prompt, decorator parses the model-emitted{"confidence": 0.x}field on stream completion (same regex shape as the existingConfidenceThresholdGuardrail) and firessession.confidenceahead of the terminal frame. Decorator self-suppresses when a runtime already invokedconfidence(...)directly withLOGPROBS_NATIVE. Skipped when structured-output mode is in play because the schema parser owns the response shape — callers add aconfidencefield to their record schema in that mode. 14 new unit tests cover record validation, the elicitation cue, parser fallbacks, runtime-explicit override, per-request override of the pipeline default, and the structured-output skip.PASSIVATION(a4fae39464) — newAgentSnapshotrecord inmodules/ai(persistable subset ofAgentExecutionContext— message, system prompt, identity columns, history, JSON-clean metadata, response type name, reason, paused-at). NewAgentPassivationstatic helper inmodules/checkpointwithpassivate(runtime, ctx, store, reason): String,resume(runtime, store, id, externalSignal, base, session), andloadSnapshot(store, id).resumemerges the snapshot onto a caller-supplied base context (which carries the runtime references — tools, memory, listeners, retry policy — that don't survive a JVM restart) and re-runsruntime.execute(...); base wins on metadata-key collision so caller-injected refs (e.g. trace context) are not clobbered by stale snapshot values. Helper lives inmodules/checkpointrather than onAgentRuntimeitself becausemodules/ai → modules/checkpointintroduces aai → checkpoint → coordinator → aicycle; the reverse direction is acyclic. Capability flag declared on every runtime — flag advertises "this runtime cooperates withAgentPassivation," honest because every runtime threadscontext.history()through its dispatch path so a resumed call observes the same conversation the paused call saw. 10 new unit tests cover snapshot round-trip, resume flow with external signal, signal-less replay of pending message, missing-checkpoint errors, metadata filtering (non-String values dropped pre-snapshot), metadata merge precedence, unique IDs across passivations, and null-arg rejection.
AiCapabilityenum gains 3 entries — total 20 capabilities (was 17).AbstractAgentRuntimeContractTest.expectedCapabilities()pin updated for all 9 framework runtimes: BuiltIn, Spring AI, LangChain4j, ADK, Embabel, Koog, AgentScope, Spring AI Alibaba, Semantic Kernel.BuiltInAgentRuntimecapability count test bumped from 13 to 16. Capability matrix inmodules/ai/README.mdextended withBE/CS/PSVcolumns plus a "Predictable-AI primitives" section documenting each capability's decorator placement, source enum, and runtime-by-runtime caveats (Spring AI Alibaba'sBUDGET_ENFORCEMENTis wall-clock-only because the runtime does not surfaceTOKEN_USAGE).
- Playwright e2e coverage for the predictable-AI primitives (
4be20c240c) —ai-budget-circuit-breaker.spec.ts,ai-confidence-elicitation.spec.ts,ai-passivation.spec.tsexercise the fullAiPipelinesession-decorator stack through Atmosphere's wire transport. Each spec drives a dedicated test handler (BudgetCircuitBreakerTestHandler/ConfidenceElicitationTestHandler/PassivationTestHandler) registered inAiFeatureTestServerso the harness seesAiBudgetExceededExceptionon the wire's error frame, theai.confidence.aggregate/.source/.tokensmetadata frames theconfidence(...)default sink emits, and the snapshot/resume round-trip across two sequential WebSocket connections.modules/integration-tests/pom.xmlbumpsatmosphere-checkpointfrom test to compile scope soPassivationTestHandlercan callAgentPassivationdirectly.modules/integration-tests/playwright.config.tsregisters the three new spec project entries.
- CLI standalone-scaffold compile against the released parent POM (
7383eb0ee2) — twentysamples/spring-boot-*/pom.xmlfiles now declare<netty.version>4.2.13.Final</netty.version>in their own<properties>block so the sample is self-contained: scaffold-then-compile against the releasedorg.atmosphere:atmosphere-project:4.0.43parent (which predates the netty bump and therefore does not declarenetty.version) no longer fails withNon-resolvable import POM: io.netty:netty-bom:pom:${netty.version}.cli/e2e-test-cli-runtime.shalso fixes a long-standing comment-vs-code drift: the script was exportingATMOSPHERE_CLI_VERSIONwhilecli/atmosphereonly ever readATMOSPHERE_VERSION_OVERRIDE, so the SNAPSHOT-against-SNAPSHOT lane silently degraded to release-pin coverage. Renaming the export aligns the script with the CLI's actual contract.
- per-request runtime extension helpers — small
attach(context, ...)/from(context)helpers (modeled on the existingCacheHint) that let callers stash framework-native composition objects inAgentExecutionContext.metadata(), so a runtime can apply them per-request without growing the unifiedAgentRuntimeSPI with framework-specific knobs. The matrix closes on 4.0.43: all eight framework runtimes have a sidecar —SpringAiAdvisors(Spring AIAdvisorchain — RAG / memory / guardrails / observability),LangChain4jAiServices(LangChain4jAiServices/TokenStream),KoogStrategy(KoogAIAgentGraphStrategyDSL),AdkRootAgent(ADKBaseAgent/SequentialAgent/ParallelAgent/LoopAgenttopology),EmbabelPromptRunner(UnaryOperator<PromptRunner>customizer applied AFTER default wiring),AgentScopeAgent(per-requestReActAgent),SemanticKernelInvocation(per-requestInvocationContext— unlocksKernelHooks,withMaxAutoInvokeAttempts, customPromptExecutionSettings),SpringAiAlibabaRunnableConfig(per-request AlibabaRunnableConfigforthreadId/checkPointId/streamMode/metadata/store), plus the cross-runtimeToolLoopPolicieshonored byBuiltInAgentRuntime's OpenAI-compatible tool loop. Initial five sidecars landed viaf1493c3f9c; the remaining four runtimes plus the lifecycle hook fan-out below landed viaeec98890fe. Also added:AgentLifecycleListener.onModelStart/onModelEnd/onModelErrorhooks withfireXxxfan-out helpers wired in all 8 framework runtimes (was Built-in only), andAiEventForwardingListeneradapter that translates lifecycle hooks to wire-formatAiEvent.Progressframes (opt-in viacontext.withListeners(...)). Each bridge ships with a unit-level*BridgeTestproving the runtime honors the sidecar.
- Quarkus extension closes the
/api/console/infoparity gap — the bundled Atmosphere Console UI gets the samesubtitle / endpoint / runtime / modepayload it gets from the Spring Boot starter, instead of falling through to the Vue defaults on a 404. NewAtmosphereConsoleInfoServlet(HttpServlet, registered at build time via a secondServletBuildItemmapped to/api/console/info) reuses the same package-prefix mode-detection heuristic asAtmosphereConsoleInfoEndpoint(org.atmosphere.{ai,agent,coordinator}.*→"ai", anything else includingManagedAtmosphereHandler→"broadcast"). Endpoint auto-detection prefers the canonical/atmosphere/ai-chatwhen registered (samples likequarkus-ai-chatship multiple@AiEndpoints), then/atmosphere/agent/*, then any other/atmosphere/*. New config keysquarkus.atmosphere.console-subtitleandquarkus.atmosphere.console-endpointmirror the Springatmosphere.console-subtitle/atmosphere.console-endpointproperties. JSON is hand-rolled so the runtime POM stays Jackson-free;AgentRuntimeResolveris reached via reflection so the servlet keeps no compile-time link tomodules/ai. Empirically verified in chrome-devtools againstquarkus-ai-chat—/api/console/infonow returns{"subtitle":"Runtime: langchain4j","endpoint":"/atmosphere/ai-chat","runtime":"langchain4j","mode":"ai"}, the Vue Console shows the runtime label in the header subtitle, and the cross-tab isolation matrix continues to pass on the Quarkus leg. - bundled Atmosphere Console now auto-detects AI vs. broadcast endpoints (
c1e8e36c7b) —/api/console/infoadds amodefield ("ai"for@AiEndpoint/@Agent/@Coordinator,"broadcast"for@ManagedServicechats);AtmosphereConsoleInfoEndpoint#detectModeclassifies via the registered handler's package prefix (org.atmosphere.{ai,agent,coordinator}.*→ ai, everything else includingManagedAtmosphereHandler→ broadcast), so the check stays compile-time independent ofmodules/aiandmodules/agent. The Vue frontend swaps empty-state copy ("Start a conversation" + "AI assistant" → "Start a broadcast" + "every connected client on this endpoint will receive it") and the default subtitle ("Runtime: " → "Multi-client broadcast chat") based on the detected mode. Closes the misleading-UI half of the cross-tab leak follow-up: pre-fix,spring-boot-mcp-serverandspring-boot-otel-chatrendered the AI-assistant copy despite being broadcast-shared by design. Empirically verified in chrome-devtools against both broadcast samples andspring-boot-ai-chat. Per-sampleatmosphere.console-subtitleoverrides still win over the mode-aware default. 5 new contract tests inAtmosphereConsoleInfoEndpointModeTestpin the four classification paths plus the override interaction. - cross-tab isolation matrix extended from 11 → 15 samples (
c1e8e36c7b) — addsquarkus-ai-chat(cross-runtime parity, proves the targeted-dispatch fix from1fbb0958f0survives Quarkus's distinctQuarkusJSR356AsyncSupportpath),spring-boot-checkpoint-agent(@Coordinatorwith analyzer/approver fleet + checkpoint store),spring-boot-ms-governance-chat(@AiEndpointwith@AgentScopeclassification interceptors stacked in front), andspring-boot-channels-chat(omnichannel@AiEndpointwith Telegram/Slack/WhatsApp/Messenger channel-bridge adapters). New fixture entries ine2e/fixtures/sample-server.tsfor the checkpoint and ms-governance samples; quarkus-ai-chat reuses the existing fixture. Out-of-scope docstring corrected to removespring-boot-channels-chat(it's actually an isolated@AiEndpoint, not a broadcast chat) and to explicitly tagspring-boot-a2a-agentas out-of-scope (A2A JSON-RPC has no two-tab Console scenario). All 15 cases pass locally in 3.5m. OpenAiCompatibleClientJavadoc placement broke JDK 26 strict mode (28703ea064) — two stacked Javadoc blocks onforwardResponsesApiUsageraiseddocumentation comment is not attached to any declarationunder-Xlint:all-Werroron JDK 26 (silent on JDK 21). Merged into a single coherent block; CI: Core (JDK 21/26) green.cli/samples.jsonandcli/atmospheretemplate map referenced deletedspring-boot-embabel-chatsample (3a9373e875) —cli/test-cli.shfailed with "samples missing README.md: spring-boot-embabel-chat". Entry removed from samples.json + template-map case statement.
- atmosphere-verifier — plan-and-verify (Meijer "Guardians of the Agents") New module modules/verifier/ + sample samples/spring-boot-guarded-email-agent/ — sealed Workflow AST, ServiceLoader-discovered PlanVerifier chain (Allowlist/WellFormed/Capability/Taint/Automaton/SmtChecker SPI), @Sink + @RequiresCapability scanners, PlanAndVerify orchestrator, WorkflowExecutor with partial-env on failure, verify CLI; sample REST + UI exercises the inbox-exfiltration scenario end-to-end (refused before any tool fires) — 74 unit + 4 boot + 6 Playwright tests, all CI green on the feature branch.
- fail-closed verifier empty-chain, JSON-escape govern. deny, deflake wasync PlanAndVerify.withDefaults + VerifyCli runChain throw / emit chain-empty violations when ServiceLoader yields no providers (P1: silent fail-open under shading / native-image / fat-jar relocation); governance-deny tool result routes every interpolated field through ToolBridgeUtils.escapeJson via a new buildGovernanceDenyJson helper (P2: backslash/newline/control char break); ChatIntegrationTest.socketStatusTransitions polls for status transition rather than asserting in the same instant the OPEN handler fires (release-pipeline timing flake). 5 new verifier tests + 6 governance-JSON tests.
- drop org.json:json — Jackson 3 only (CVE hygiene) RoomProtocolCodec + SimpleRestInterceptor migrated to tools.jackson; brace-balanced reader preserves SwaggerSocket header/body chunk semantics; ALLOW_SINGLE_QUOTES kept for wire compatibility; org.json removed from parent + 3 spring-boot samples.
- bump version to 4.0.41
- prepare for next development iteration 4.0.42-SNAPSHOT
atmosphere-a2aretracked to A2A v1.0.0 (a2aproject/A2A@v1.0.0, released 2026-03-12). The pre-1.0 wire surface was the slash-style method names (message/send,tasks/get, …) and a polymorphicPartenvelope; both are gone in v1.0.0.- JSON-RPC method names switched to PascalCase per spec §9.4 —
SendMessage,SendStreamingMessage,GetTask,ListTasks,CancelTask,SubscribeToTask, the four{Create,Get,List,Delete}TaskPushNotificationConfigoperations, andGetExtendedAgentCard. The pre-1.0 slash names and the oldtasks/pushNotification/*path are aliased to their v1.0.0 equivalents at handler entry, with a one-time WARN per legacy method seen — existing Atmosphere clients keep working through the transition. - HTTP+JSON / REST binding added — colon-verb endpoints
(
POST /tasks/{id}:cancel,POST /tasks/{id}:subscribe,POST /message:send/:stream),pushNotificationConfigsCRUD URLs, andGET /extendedAgentCardare recognized byA2aHandler. REST requests are translated to JSON-RPC envelopes and dispatched through the same handler so the two bindings agree by construction (Mode Parity invariant #7). - Type schema rewrite under
org.atmosphere.a2a.types:Partcollapses three legacy subtypes (TextPart/FilePart/DataPart) into a single record carrying atext | raw | url | dataoneof plus sharedmetadata,filename,mediaType. The deserializer continues to accept the pre-1.0{"type":"text",…}/{"kind":"text",…}envelopes for migration.Message.roleis now theRoleenum (ROLE_USER/ROLE_AGENTper ADR-001 ProtoJSON). Lower-case legacy forms parse for back-compat.TaskStateaddsSUBMITTED(the v1.0.0 ack-before-work state) and emits its proto-JSON name on the wire (TASK_STATE_WORKING, …).Task.messagesis renamed toTask.history;TaskStatusis promoted to a top-level type and carries atimestamp; both update events (TaskStatusUpdateEvent,TaskArtifactUpdateEvent) gaincontextIdandmetadataand drop the redundantfinalflag.AgentCardgainssupportedInterfaces(so an agent can advertise JSON-RPC + HTTP+JSON at distinct URLs), structuredAgentProvider,AgentCardSignature,iconUrl, structuredSecurityScheme/SecurityRequirement, andextendedAgentCardmoves intoAgentCapabilities(wassupportsAuthenticatedExtendedCard). The pre-1.0 top-levelguardrailsfield is no longer modeled — guardrails surface as anAgentExtensiononAgentCapabilities.extensionsunderhttps://atmosphere.async-io.org/extensions/guardrails/v1.- New types added for the missing v1.0.0 surface:
AgentInterface,AgentExtension,AgentSkill(replacesSkill),SecurityRequirement,SecurityScheme+APIKey/HTTPAuth/OAuth2/OpenIdConnect/MutualTls,OAuthFlows+ the three non-deprecated flow shapes,AuthenticationInfo,TaskPushNotificationConfig, and the response wrappersSendMessageResponse,StreamResponse,ListTasksResponse,ListTaskPushNotificationConfigsResponse.
- Pagination + history honored:
GetTaskreadshistoryLength;ListTasksreadspageSize(clamped 1..100, default 50),pageToken, optionalstatusfilter; the response is the v1.0.0ListTasksResponsewithnextPageToken,pageSize,totalSize.SubscribeToTaskreturns-32004UnsupportedOperationErroron a terminal task. - Push-notification methods: handlers route the four CRUD names
but return
-32003PushNotificationNotSupportedError—AgentCapabilities.pushNotificationsis advertised asfalse(Runtime Truth invariant #5; deliveries are not yet wired so the capability flag stays honest). - SSE chunks emitted by
A2aHandler.handleSseStreamingare now spec-compliantStreamResponseenvelopes carrying anartifactUpdateoneof variant (was a custom{"artifact":{…}}shape pre-1.0). - Coordinator
A2aAgentTransportupdated to send/receiveSendMessage/SendMessageResponseand to accept both the v1.0.0 and pre-1.0 task-status shapes when classifying failure replies. modules/agentAgentProcessorupdated to construct the v1.0.0AgentCardand surface guardrails via the extension URI above. Spring BootWellKnownAgentFilterTestfixture rewritten for the new card constructor.
- Tool-call admission seam (
1def61ddf0) —PolicyAdmissionGate.admitToolCallbuilds a syntheticAiRequestwhose metadata carriestool_name,action, and an argument preview so MS-schema rules overtool_namefire before the tool's executor runs.ToolExecutionHelperconsults the gate on every@AiTooldispatch; the canonical MS example{field: tool_name, operator: eq, value: delete_database, action: deny}fires without operator plumbing. OWASP A02 upgraded from PARTIAL to COVERED. @AgentScope.postResponseCheck(2913da1b81) — when enabled on a high-stakes scope,ScopePolicyre-classifies the streamed response text against the declared purpose. OUT_OF_SCOPE responses become Deny with apost-response:prefix; errors fail-open on the response path (bytes already on the wire).POLITE_REDIRECTbreaches downgrade to Deny because Transform can't rewind a stream.- Cross-provider governance contract (
613d216019) —AbstractAgentRuntimeContractTest.policyDenyBlocksRuntimeExecuteis inherited by all seven runtime adapters (Built-in, Spring AI, LangChain4j, ADK, Embabel, Koog, Semantic Kernel); the "deny before runtime" guarantee is now a build-time invariant for each provider. - Per-request
ScopePolicyinstall (334bde4969) — an interceptor can write aScopeConfigunderScopePolicy.REQUEST_SCOPE_METADATA_KEYand the pipeline / streaming session / admission gate install a transientScopePolicyahead of endpoint-level policies for that one turn. Classroom sample uses this for per-room scope (math / code / science / general) — one@AiEndpointhosts four personas, each with its own purpose and forbidden-topic set.perRequestScopeBlocksRuntimeExecuteextends the cross-provider contract to the per-request path. - Admin console governance views — three Vue views under the existing
Atmosphere Console (
/atmosphere/console/) poll/api/admin/governance/{policies,decisions,owasp}on live intervals. Tabs auto-hide when governance is not installed. Verified end-to-end against the classroom sample via chrome-devtools (tabs render, OWASP matrix shows 7 Covered / 1 Partial / 1 Design / 1 Not-addressed, zero console errors). - Persistent
AuditSinkSPI —GovernanceDecisionLog.addSink(AuditSink)fans every admission decision out to registered sinks while keeping the ring buffer authoritative for the admin console. Sink failures are isolated: one unreachable Kafka broker does not take down the pipeline.AsyncAuditSinkwraps a blocking delegate with a bounded drop-on-full queue so the admission thread never blocks on IO (Backpressure invariant #3). Two reference modules ship:atmosphere-ai-audit-kafka(KafkaAuditSink→ JSON to any topic) andatmosphere-ai-audit-postgres(JdbcAuditSink→ JDBC upsert with schema auto-create, works against any JSR-221DataSource; tests exercise H2 in-memory). The JSON shape matches MS Agent Governance Toolkit'saudit_entryso downstream SIEM consumers of either system can read both.
@AgentScopeannotation +ScopeGuardrailSPI (ba7ddf3688) — architectural goal-hijacking prevention. Annotation declarespurpose,forbiddenTopics,onBreach(POLITE_REDIRECT / DENY / CUSTOM_MESSAGE), andtier(RULE_BASED / EMBEDDING_SIMILARITY default / LLM_CLASSIFIER opt-in).ScopePolicymapsScopeGuardrailoutcomes to admit/transform/deny semantics per the breach policy.RuleBasedScopeGuardrailships with built-in hijacking probes for code, medical, legal, and financial patterns so the McDonald's failure mode is caught without operator-declared topic enumeration.- System-prompt hardening + endpoint auto-wiring (
a11239cac3) —AiEndpointProcessorreads@AgentScopeon the endpoint class and auto-installs aScopePolicyahead of user-declared policies;AiPipelineprepends an unbypassable scope-confinement preamble to the system prompt on everyexecute()call, surviving sample-level substitutions. - Sample-hygiene CI lint + 12-sample retrofit (
287a5f9b71) —SampleAgentScopeLintTestwalkssamples/and fails the build on any@AiEndpointmissing@AgentScope(or lacking a non-blankjustificationwhenunrestricted = true). All 12 existing sample endpoints retrofitted — 11 declareunrestricted = truewith specific justifications (production deployments replace with a scoped@AgentScope);ReviewExtractordeclares a real scoped purpose. - Embedding-similarity scope tier (
2c856bd00d) — default tier. Resolves anEmbeddingRuntimevia ServiceLoader; caches the purpose vector (and every forbidden-topic vector) on first use; rejects when cosine similarity falls belowsimilarityThreshold. Absent runtime admits-with-warning so the rule-based tier remains a safe fallback. - LLM-classifier scope tier (
5b8b6f51da) — opt-in tier for high-stakes scopes. Zero-shot YES/NO classifier over the resolvedAgentRuntime; tolerant parser handles**YES**/YES./*no*/ "Not sure" edge cases; ambiguous verdicts fall through to admit so LLM quirks don't over-reject; timeouts and runtime errors fail-closed at theScopePolicylayer. - Governance audit trail (
a534f5e462) —AuditEntryrecords everyGovernancePolicy.evaluatedecision with identity, reason, context snapshot (redaction-safe: truncated message, primitive-only metadata), andevaluation_ms.GovernanceDecisionLogis a thread-safe ring buffer (default 500 entries) installed viaGovernanceDecisionLog.install(capacity). Surfaced viaGET /api/admin/governance/decisions?limit=N.GovernanceTraceremits an OpenTelemetry span per evaluation through reflective classpath detection — OTel stays an optional dependency. - ms-governance-chat feature-parity retrofit (
3fc8ead4cb) — the sample now declares@AgentScope(purpose = "Customer support for Example Corp — orders, billing, ...")and loads 9 MS-schema rules mirroring MS'scustomer-service/main.pyexample (destructive SQL, legal/media/exec escalation, human-request auto-escalate, PII shapes, password disclosure, discount-limit enforcement, plus anaudit-action rule for code-request probing). - OWASP Agentic Top-10 self-assessment matrix (
712c57e4e8) —OwaspAgenticMatrix.MATRIXpins 10 rows (6 COVERED, 2 PARTIAL, 1 DESIGN, 1 NOT_ADDRESSED) with evidence classes, test references, and consumer grep patterns per row.OwaspMatrixPinTestfails the build when any evidence class is renamed or removed — structural answer to the v4 §4 discipline risk. Served over HTTP atGET /api/admin/governance/owaspforagt verify-style compliance consumers.
GovernancePolicySPI (0ace2b6947) — declarative policy identity (name/source/version) plusPolicyContext→PolicyDecisionevaluation. Vocabulary aligned with OPA/Rego and Microsoft Agent Governance Toolkit at the evaluate-decision level (admit/deny/ transform). The SPI is strictly additive — existingAiGuardrailwiring keeps working unchanged.GuardrailAsPolicy+PolicyAsGuardrailadapters (efefaea40a) — every existingAiGuardrailis reachable as aGovernancePolicyviaGuardrailAsPolicy; policies land on the currentAiPipelineadmission seam viaPolicyAsGuardrail.Transformdecisions on the post-response path are downgraded topasswith a warning (streamed text is not retroactively rewritable).- YAML
PolicyParser+PolicyRegistry(83e5c2dafd) — default parser reads YAML via SnakeYAML'sSafeConstructor(no arbitrary class instantiation). Built-in types:pii-redaction,cost-ceiling,output-length-zscore— factories wrap the shipped guardrails with the identity from the YAML entry.modules/aideclares SnakeYAML as an explicit runtime dep so bare-JVM / Jetty-embedded deployments get the parser out-of-the-box. Parser discovered via ServiceLoader; additional formats (Rego, Cedar) plug in by shipping anotherPolicyParserservice entry. - Native
AiPipelinewiring (9ac9ed1d6c) —AiPipelineaccepts aList<GovernancePolicy>on a new constructor, evaluates them in a dedicated pre-admission loop (fail-closed on exception per Correctness Invariant #2), and merges them onto the existingGuardrailCapturingSessionfor post-response viaPolicyAsGuardrail.pipeline.policies()accessor exposes the installed list so admin surfaces can enumerate them without re-parsing YAML. Response cache skips when policies are present so each turn re-evaluates. - Spring + endpoint-processor bridge (
9d7b75be78) —AiEndpointProcessor.instantiatePolicies()merges ServiceLoader andPOLICIES_PROPERTYsources with dedup byname(); policies are wrapped throughPolicyAsGuardrailand threaded onto every@AiEndpointin the app.AtmosphereAiAutoConfigurationnow bridges Spring-managedGovernancePolicybeans onto the same property so the default path "drop a YAML file on the classpath" just works. Parity test (PolicyPlaneSourceParityTest) pins YAML / programmatic / ServiceLoader sources to identical admission decisions. - Classroom sample retrofit (
aaac15f725) —samples/spring-boot-ai-classroom/src/main/resources/atmosphere-policies.yamldeclares a PII redaction and a z-score drift detector;PoliciesConfigreads it at startup and publishes the list toPOLICIES_PROPERTY. Demonstrates the key promise: change YAML, restart, governance changes — zero code edits. - Admin introspection (
b973aa2828) —GovernanceControllerreadsPOLICIES_PROPERTYfor per-policy identity and distinct-source counts;/api/admin/governance/policiesand/api/admin/governance/summaryHTTP endpoints expose the live list;AtmosphereAdmin.overview()reports the policy count alongside the AI runtime name. - Microsoft Agent Governance Toolkit YAML parity —
YamlPolicyParserauto-detects the MS schema (documents with top-levelrules:) and produces aMsAgentOsPolicythat preserves MS's first-match-by-priority rule-evaluation semantic. All nine comparison operators (eq,ne,gt,lt,gte,lte,in,contains,matches) and all four actions (allow,deny,audit,block) are honored. Context map bridgesAiRequestfields (message,model,user_id, …) and every metadata entry to rule field names.MsAgentOsYamlConformanceTestloads MS's own example YAMLs (copied unmodified frommicrosoft/ agent-governance-toolkit@April-2026) and asserts byte-for-byte interop.
AgentStateSPI (a0fd3fc48c) — unifies conversation history, durable facts, daily notes, working memory, and hierarchical rules under one runtime-agnostic interface. File-backed default (FileSystemAgentState) reads and writes an OpenClaw-compatible Markdown workspace.AutoMemoryStrategypluggable with four built-ins (EveryNTurns,LlmDecided,SessionEnd,Hybrid).AgentStateConversationMemoryis a thin shim over the legacyAiConversationMemory.AdkAgentRuntimeseeds its ADKSessionfromcontext.history()(closes Correctness Invariant #5 gap whereCONVERSATION_MEMORYwas advertised but silently dropped).AgentWorkspaceSPI (d4b3e341c7) — agent-as-artifact. ServiceLoader discovery withOpenClawWorkspaceAdapter+AtmosphereNativeWorkspaceAdapter. OpenClaw canonical layout runs on Atmosphere without conversion.ProtocolBridgeSPI (853cccc4aa) —InMemoryProtocolBridgeelevated to first-class bridge, same footing as wire bridges.ProtocolBridgeRegistryenumerates active bridges.AiGatewayfacade (4d48c3eb4a,43870cb537) — single admission point for outbound LLM calls.PerUserRateLimiter, pluggableCredentialResolverandGatewayTraceExporter.BuiltInAgentRuntimenow routes every dispatch throughAiGatewayHolder.get().admit(...)— Correctness Invariant #3 enforced at the runtime boundary.AgentIdentitySPI (f4df5603a7) — per-user identity, permissions, credentials, audit, session sharing.PermissionModelayers over per-tool@RequiresApproval.AtmosphereEncryptedCredentialStoreuses AES-GCM with a 256-bit key and per-entry random IV; decryption failure is fail-closed.ToolExtensibilityPointSPI (59f7ecd197) — bounded tool discovery (ToolIndex+DynamicToolSelector) and pluggable per-user MCP trust (McpTrustProviderwithCredentialStoreBackeddefault).SandboxSPI (818f531216,1e2daa1143) — pluggable isolated execution.DockerSandboxProviderdefault + dev-onlyInProcessSandboxProvider.@SandboxToolannotation. Default limits 1 CPU · 512 MB · 5 min · no network.NetworkPolicyenum (NONE/GIT_ONLY/ALLOWLIST/FULL) replaces the boolean network flag; Docker provider labels containers with the resolved policy.AgentResumeHandle+RunRegistry(2ae4e8835b,27425b15f6) — mid-stream reconnect primitive with boundedRunEventReplayBuffer.StreamingSession.runId()default method returns the id registered withRunRegistry;DurableSessionInterceptorstashes theX-Atmosphere-Run-Idheader in a request attribute so the ai module can reattach without the durable-sessions module depending on atmosphere-ai.- Wire
ProtocolBridgeimplementations (74d3ecbd6e) for MCP, A2A, AG-UI, and gRPC so the admin control plane can answer "which agents are reachable via which protocol?" across every transport.
spring-boot-personal-assistant(2a7ae59a41) — primary coordinator delegates to scheduler / research / drafter crew viaInMemoryProtocolBridge. Ships an OpenClaw-compatible workspace (AGENTS.md/SOUL.md/USER.md/IDENTITY.md/MEMORY.md) plus Atmosphere extension files (CHANNELS.md/MCP.md/PERMISSIONS.md).spring-boot-coding-agent(ae9c2e174c) — clones a repo into a Docker sandbox and reads files.SandboxProviderdiscovered viaServiceLoader; defaults to Docker, falls back to in-process for dev.
ControlAuthorizer.DENY_ALLandREQUIRE_PRINCIPALas explicit admin-plane baselines alongside the existingALLOW_ALL.ALLOW_ALLis documented as non-production; operators wireREQUIRE_PRINCIPALon top of their transport auth (Spring Security, Quarkus security) for production deployments.
BusinessMetadata— standard keys (business.tenant.id,business.customer.id,business.session.revenue,business.event.kind, ...) with anEventKindenum. Published to SLF4J MDC on the dispatching virtual thread and cleared infinallyso Dynatrace / Datadog / OTel log exporters propagate tenant + customer + revenue tags onto the active span for every agent turn.FactResolverSPI +DefaultFactResolver— injects deterministic facts (time, user identity, plan tier, customapp.*keys) into the system prompt before every turn. Resolution order matchesCoordinationJournal/AsyncSupport: framework-property bridge (Spring beans) →ServiceLoader→ process-wide holder → default. Newline / tab / control characters in values are escaped so fact values cannot reshape the instruction context.PiiRedactionGuardrail— regex-based detection of email, phone, credit card, US SSN, IPv4. Redacts on the request path, Blocks on the response path (the SPI cannot rewrite an already-emitted stream, so default-mode log-only signalling was security theatre).OutputLengthZScoreGuardrail— rolling-window drift detector; Blocks responses more than N standard deviations above the window mean. Opt-in viaatmosphere.ai.guardrails.drift.enabled=true.- Agent-to-Agent Flow Viewer —
GET /api/admin/flowandGET /api/admin/flow/{coordinationId}render theCoordinationJournalas a graph (nodes = agents, edges = dispatch count + success / failure / avg-duration). Edge attribution is keyed per-coordinationIdso concurrent tenant runs stay scoped. - Run reattach consumer —
AiEndpointHandlernow reads theX-Atmosphere-Run-Idheader on reconnection, looks up the liveAgentResumeHandleviaRunRegistry, and replays the buffered events onto the new resource. Closes the "producer present, consumer absent" gap in the original primitive wire-in.
PiiRedactionFilter(c2076a41a1) —BroadcasterFilterthat rewrites email / phone / credit-card / US SSN / IPv4 tokens in-flight before bytes reach the client. Atmosphere owns the broadcaster, so rewriting happens on the same thread that would have flushed the unfiltered bytes — a pure orchestration layer can only block a streaming response, never redact it mid-flight. Auto-installs on every present and future broadcaster whenatmosphere.ai.guardrails.pii.enabled=true. Replacement token configurable viaatmosphere.ai.guardrails.pii.replacement(default[REDACTED]). Listener ownership is symmetric — aDisposableBeanremoves the installed listener on shutdown.
CostAccountantSPI +CostCeilingAccountantimpl (1e06de99bb) — bridgesTokenUsageevents from any runtime intoCostCeilingGuardrail.addCost(tenantId, dollars). Installed automatically when both aCostCeilingGuardrailbean and aTokenPricingbean are present on the Spring Boot classpath. Closes the "observability as dashboard" gap: cumulative tenant cost now gates outbound dispatch instead of only surfacing on a Grafana panel.TokenPricingSPI — per-model dollar-per-token schedule. Applications supply their own pricing (provider quotes change); no baked-in table.CostAccountingSessiondecorator — wraps every@Promptsession inAiStreamingSession.dispatchwhenever theCostAccountantHolderis non-NOOP. CapturesTokenUsagefrom every runtime via the existingStreamingSession.usage(...)hook, routes the cost through the accountant, then forwards to the delegate so the runtime call path is unchanged. Tenant MDC is snapshotted at construction so Reactor-thread usage events don't collapse into the__default__bucket.CostCeilingGuardrail(c2076a41a1) — inspects requests before dispatch; blocks outbound@Promptwhen the tenant's cumulative cost is at or above the per-tenant budget. Per-tenant buckets keyed bybusiness.tenant.idMDC; turns without a tenant tag share a__default__bucket.resetTenant(...)/resetAll()on an operator-driven schedule for monthly billing boundaries.
OutputLengthZScoreGuardrailtenant partition (c2076a41a1) — the rolling-window drift detector now partitions its window bybusiness.tenant.id, so a noisy tenant can no longer poison other tenants' baselines. Single-tenant deployments fall back to a shared__default__bucket and behave unchanged.
RunReattachSupport(c2076a41a1) — stateless helper extracted fromAiEndpointHandler.reattachPendingRun. Replay writes the joined buffer directly toresponse.getWriter()(U+001E between events) on reconnection. Unit-tested standalone.RunEventCapturingSessionproducer wire (8156842fd4) — closes the "consumer wired, producer missing" half of the first reattach landing. Mirrors everysession.send/complete/errorinto the run'sRunEventReplayBufferso reconnecting clients have something to replay.- Reattach wire fidelity (
69d5dad403) — replay emitsAiStreamMessageJSON frames matching the live-stream schema (one parser, two paths);AiEndpointHandlerroutes timeout / exception terminals through the capturing session so replayed streams end with a proper error envelope. - P0 reattach ownership + filter-chain replay (
ffedda4b7e) — replay refuses when the reconnecting caller's resolveduserIddoes not match the run's registereduserId(closes a bearer-token cross-user leak). Anonymous runs keep the open-mode carve-out so demo deployments still work. Every replay frame is routed through the broadcaster'sBroadcastFilterchain soPiiRedactionFilterand downstream content filters apply identically to replay and live frames — a direct-writer path previously bypassed them. RunEventCapturingSession.handoff()forwarding (ff8c2d5542) — the defaultStreamingSession.handoffthrowsUnsupportedOperationException; the capturing wrapper inherited it and broke orchestration-primitives handoffs. Now delegates.
atmosphere.admin.http-read-auth-requiredopt-in flag (2d3ee5afc3) — when true,GET/HEAD/OPTIONSon/api/admin/*require the same principal chain as the write-side gate (minusControlAuthorizer). Default off so local demo consoles keep working; multi-tenant operators exposing/api/admin/*on a routable network flip one flag.AdminApiAuthFilter(Spring) +AdminReadAuthFilter(Quarkus JAX-RS@Provider) — symmetric enforcement across starters.
- Fourth principal source on Quarkus admin writes
(
b3d032d00c) —X-Atmosphere-Authheader validated via constant-time compare againstatmosphere.admin.auth.token. A synthetic principal is admitted on match. Intended for sample fixtures and operator tooling that have not yet integrated Jakarta Security; production stacks still resolve viaSecurityContext.getUserPrincipal()first. - Malformed journal timestamp returns 400 (
9aa1651f3f) — previously 200 with an error-item array, which masked client errors and broke Spring / Quarkus API parity. Now matches the SpringAtmosphereAdminEndpointbehavior (Correctness Invariant #4).
AtmosphereFaviconAutoConfiguration(98c6ae408b,2d3ee5afc3) — serves/favicon.icoand/favicon.pngwith the Atmosphere logo PNG on every app using either spring-boot starter, killing the default 404 on the admin UI, console UI, and every sample. Opt out withatmosphere.favicon.enabled=false. Ships as a nested@RestControllerinside the@AutoConfigurationclass; a@Beanfactory introduced in the initial commit produced a duplicateatmosphereFaviconControllerbean and triggeredAmbiguous mappingat startup — removed in the fix.
- SVG coordination-graph visualizer (
d1245d7780) — new admin console tab renders/api/admin/flowas a circle-layout SVG. Nodes are agents, edges carry dispatch count / success / failure / average duration (red on failure, arrowheads for direction). Optionalcoordination-iddrilldown andlookback-minutesfilter. Zero external graph library. Mirrored acrossspring-boot-starterandspring-boot3-starteradmin assets.
RuntimeGatewayAdmissionParityTest(d5f8a03174,81c135cf5c,1632360f7f) — source-level parity scan with brace-balanced method-body extraction; every*AgentRuntime.{java,kt}must calladmitThroughGatewayfrom its designated dispatch methods or the build fails. Catches a regression where a runtime's dispatch path silently bypasses rate limiting and credential policy.- Seven exec-level
*GatewayAdmissionTestfiles —SpringAiGatewayAdmissionTest(48a38d58c6); LangChain4j, ADK, Semantic Kernel (Java) and Koog, Embabel (Kotlin) together (1006a4301d); plus the existingBuiltInExecuteWithHandleGatewayTest. Each installs a countingAiGateway.GatewayTraceExporterand drivesruntime.execute(...)so an admission entry with the correct provider label is captured at the exec level, not just source-level grep. ChangelogClaimsTest(94404ce023) — pins theAgentStateOpenClaw workspace layout andRunEventReplayBufferbound so CHANGELOG-to-code drift breaks the build.
samples/spring-boot-reattach-harness(65f2f6ce5f) —SlowEmitterChatplus aSyntheticRunControllerthat pre-populates theRunRegistryso Playwright can drive theHTTP → reattachPendingRun → replayPendingRunwire with deterministic timing.e2e/tests/reattach.spec.tsruns on every push via a dedicatedfoundation-e2e.ymljob on port 8096 — the reattach contract is proven end-to-end, not just at unit level.
BusinessMdcBenchmark(82899e5145) — JMH harness pinning the cost of the per-turnbusiness.*MDC snapshot → apply → clear cycle thatAiEndpointHandler.invokePromptruns on every dispatch. Baseline, six-key production, and empty-snapshot scenarios, so a regression on the hot path shows as numbers, not intuition.
- Admin HTTP writes now enforce authentication in addition to
the feature flag.
guardWrite(HttpServletRequest, action, target)resolves a Principal from the servletUserPrincipal, the AtmosphereAuthInterceptor-set attribute, or theai.userIdattribute, then consultsControlAuthorizer. The earlier feature-flag-only gate let any anonymous caller mutate state once the flag was flipped. Correctness Invariant #6 (Security). - MCP write tools forward the authenticated principal to
ControlAuthorizer.authorize(...). Previously every tool passednull, soREQUIRE_PRINCIPALpermanently denied andALLOW_ALLpermanently admitted regardless of identity. NewIdentityAwareToolHandlerfunctional interface threads the servlet-resolved principal throughMcpProtocolHandler.executeToolCall. AiGatewayadmission on cancel-capable dispatch paths.BuiltInAgentRuntime.doExecuteWithHandleandKoogAgentRuntime.executeWithHandlenow calladmitThroughGateway— parity with the plainexecutepath so rate limits and credential policies fire on every mode (Correctness Invariant #7 — mode parity).- Business MDC lifecycle. The MDC population was previously done on the servlet thread (wrong thread — VT logs never saw it) and never cleared. Snapshot on the servlet thread, apply on the VT dispatcher with try/finally clear, so every log record during the turn carries the tags and the VT pool starts clean on the next turn.
- Flow graph attribution under interleaved coordinations.
FlowController.buildGraphpreviously carried a flatcurrentCoordinatorcursor — concurrent runs misattributed every second edge. Now maintains acoordinationId → coordinatorNamemap. - User
@AiEndpointpaths get Spring + ServiceLoader guardrails.AiEndpointProcessormerges annotation-declared guardrails withServiceLoader.load(AiGuardrail.class)and the framework-property bridge so annotation-declared endpoints are no longer starved of the auto-wired guardrail set. NewAiGuardrail.GUARDRAILS_PROPERTYmirrors theCoordinationJournalbridge key. - Foundation E2E stops skipping the Docker sandbox regression.
SKIP_SANDBOX_E2E=truepreviously hid the command-injection hardening; removed fromfoundation-e2e.ymlso the clone+read spec runs on every PR. ubuntu-latest ships with Docker — the new workflow also verifies its presence early. - Sample boot modernization.
spring-boot-coding-agentreverted fromapplication.propertiestoapplication.yml; both samples addspring-boot-starter-actuator;foundation-e2e.ymlboots via./mvnw spring-boot:runand waits on/actuator/healthviawait-oninstead of shelling out tocurland pre-building a fat jar.
- Jetty 12.0.33, Tomcat 11.0.21, Kafka 3.9.2 (
8e4b63e18a) — closes 13 Dependabot advisories (1 critical, 5 high, 3 medium). - Bouncy Castle 1.84 pinned in
dependencyManagement(246c29bc75) — closes LDAP-injection and risky-crypto advisories against the 1.82 tree thatdocker-java-core 3.7.0pulls in transitively. Provided-scope only (Docker sandbox path); no runtime fat-jar drift. - protobuf 4.34.1 pinned to match
protoc(4876779978) —grpc-protobuf 1.80.0still pulledprotobuf-java 3.25.8transitively, soprotoc 4.x-generated sources failed to compile. - MCP SDK 1.0.0 → 1.1.1 (
da57094ce6). - React / React DOM 19.2.5 in lockstep (
8226e28fcb) — React requires an exact version match betweenreactandreact-dom; a partial Dependabot bump broke every jsdom-backed test withensureCorrectIsomorphicReactVersion. HtmlEncoderregistered as a CodeQL XSS sanitizer (b5f184e417) — resolves four false-positivejava/xsscode-scanning alerts.
AdminResourcesurvivesIllegalStateException: UT000048(e2d254ad68) — resteasy-reactive dispatches on Vert.x, so@Context HttpServletRequestattribute access throws on the admin write path. Attribute access is swallowed (attributes cannot fire on Vert.x anyway) andX-Atmosphere-Authis read via@Context HttpHeaders, which works on both transports.
GrpcWasyncTransportTeststatus-poll 2s → 5s (1586d91246) — wAsync updatesSocket.status()on its dispatch thread after theCLOSEcallback returns; the 2s polling cap was too tight on JDK 26 where scheduler latency between callback and CAS is observably longer.
FileSystemAgentStatecross-scope bleed (ad850f9f35).MEMORY.mdandmemory/YYYY-MM-DD.mdnow live underusers/<userId>/agents/<agentId>/so facts never bleed across users or agents (Correctness Invariant #6, default deny on cross-scope access). Three new isolation tests cover cross-user, cross-agent, and cross-scope delete boundaries.
atmosphere newis now sample-clone based (b7f98d42f0,0b9a8f194d). The CLI no longer ships a mustache-based scaffold.atmosphere new <name> --template <t>now sparse-clones the matching sample fromcli/samples.jsonand rewrites the clonedpom.xmlso itsorg.atmosphere:atmosphere-projectparent resolves from Maven Central (pins the version from SNAPSHOT to the release incli/samples.json, drops the reactor-relative<relativePath>, disables repo-local checkstyle/pmd bindings). The resulting project compiles standalone with plainmvn compile.- Nine templates in
cli/atmospherecmd_new:chat,ai-chat,ai-tools,mcp-server,rag,agent,koog,multi-agent,classroom. Each maps 1:1 to a sample incli/samples.json;multi-agentandclassroomare new starters exposing the 5-agent A2A fleet and the AI-classroom Spring Boot + Expo RN sample respectively. create-atmosphere-app(npx) rewritten as a thin delegating shim (944b190f43). Drops the old JBang branch and the 240-line inline Java/HTML fallback, resolves the installedatmosphereCLI on PATH, and execsatmosphere new <name> --template <t> [--skill-file <f>]. Prints an actionable install hint if the CLI is missing.TEMPLATESlist synchronized with the shell CLI's nine entries.
generator/AtmosphereInit.java+AtmosphereInitTest.java+generator/templates/handler/**generator/templates/frontend/**+generator/templates/{Application.java,application.yml,pom.xml}.mustachegenerator/test-generator.sh+.github/workflows/generator-ci.yml(b7f98d42f0). The JBang mustache scaffold is fully gone.generator/ComposeGenerator.javaand itsgenerator/templates/compose/**tree remain — they back the parametric skill-file driven multi-module scaffold invoked byatmosphere compose, which has no single-sample equivalent.
cli/atmospherebash fallback tree —create_minimal_project,create_chat_handler,create_ai_chat_handler,create_agent_handler,create_index_html(~430 lines).cmd_newnow always clones; there is no fallback path.--groupflag onatmosphere newandcreate-atmosphere-app. Samples ship with their own groupId; passing--groupprints a deprecation warning and is ignored. Rename the groupId inpom.xmlandsrc/main/javaby hand after scaffolding if needed.
4.0.36 - 2026-04-13
Every bullet in this section is grounded in a real commit on main at the
time of release; commit hashes are listed where the attribution matters.
- Microsoft Semantic Kernel adapter (
atmosphere-semantic-kernel). SeventhAgentRuntimeimplementation backed by Semantic Kernel'sChatCompletionService. Streams via the SK streaming chat API, honors system prompts, threadsAgentExecutionContextinto the SK invocation context, and reports token usage. Tool calling is deferred in 4.0.36 (SK's JavaKernelFunctiontool binding is not yet bridged throughToolExecutionHelper.executeWithApproval).SemanticKernelEmbeddingRuntimeships alongside for embedding support via SK'sTextEmbeddingGenerationService; blocks the reactive response at a 60s ceiling to avoid pinning a virtual thread on a hung service.
ToolApprovalPolicysealed interface (c83469a478). Four permitted implementations:annotated()(default, honors@RequiresApproval),allowAll()(trusted test fixtures),denyAll()(preview / shadow mode, no invocation ever runs), andcustom(Predicate<ToolDefinition>)for runtime-dependent decisions. Attach viaAgentExecutionContext.withApprovalPolicy(...).ExecutionHandlecooperative cancel for in-flight executions viaAgentRuntime.executeWithHandle(context, session). Idempotentcancel(), terminalwhenDone()future,isDone(). Runtime cancel primitives (verified from source):- Built-in:
HttpClientrequest + SSEInputStream.close() - Spring AI:
reactor.core.Disposable.dispose()on the streamingFlux - LangChain4j:
CompletableFuture.completeExceptionally+AtomicBooleansoft-cancel flag consulted in the streaming response handler - Google ADK:
AdkEventAdapter.cancel()→io.reactivex.rxjava3.disposables.Disposable.dispose()on the Runner subscription - JetBrains Koog:
AtomicReference<Job>captured byexecuteInternal→Job.cancel()+ virtual-threadThread.interrupt()fallback + immediatedone.complete(null)backstop - Semantic Kernel, Embabel: no-op sentinel (
ExecutionHandle.completed()) — neither runtime overridesexecuteWithHandle, documented as a known gap.
- Built-in:
AgentLifecycleListener— observability SPI withonStart,onToolCall,onToolResult,onCompletion,onError. Attach viaAgentExecutionContext.withListeners(List<AgentLifecycleListener>).AbstractAgentRuntimefires start / completion / error via protectedfireStart/fireCompletion/fireErrorhelpers, so the five runtimes that extend it (Built-in, Spring AI, LC4j, ADK, SK) get lifecycle events automatically. Tool events fire through the staticfireToolCall/fireToolResultdispatchers used by every tool bridge. Koog and Embabel implementAgentRuntimedirectly and do not yet fire start / completion / error (documented exclusion indocs/reference/lifecycle-listener.md).EmbeddingRuntimeSPI withfloat[] embed(String),List<float[]> embedAll(List<String>),int dimensions(),isAvailable(),name(),priority(). Five implementations ship; service-loader resolution picks the highest-priority available one at runtime:SpringAiEmbeddingRuntime— priority 200LangChain4jEmbeddingRuntime— priority 190SemanticKernelEmbeddingRuntime— priority 180EmbabelEmbeddingRuntime— priority 170BuiltInEmbeddingRuntime— priority 50 (zero-dep OpenAI-compatible fallback)
- Per-request
RetryPolicyonAgentExecutionContext. Record shape:(int maxRetries, Duration initialDelay, Duration maxDelay, double backoffMultiplier, Set<String> retryableErrors). Only the Built-in runtime currently honors the per-request override; framework runtimes inherit their own native retry layers and the capability is Built-in-only in 4.0.36 (per the pinned capability matrix inAbstractAgentRuntimeContractTest.expectedCapabilities()). - Pipeline-level
ResponseCache(3e1fc6e4a7). SHA-256CacheKeyover model, system prompt, message, response type, conversation history, tool names, and content parts (text / image mime+length / audio mime+length / file mime+length+bytes). Session-ID-independent so identical prompts hit the same cache line.CacheHintmetadata on the context selects policy (CONSERVATIVE,AGGRESSIVE,NONE). - Multi-modal
Content— sealedContenttype withText,Image,Audio,Filesubtypes. Wire frames carry base64-encoded payloads with explicitmimeTypeandcontentType. Runtimes that do not support multi-modal input declare the exclusion in theircapabilities()set (Correctness Invariant #5 — Runtime Truth). session.toolCallDelta()+AiCapability.TOOL_CALL_DELTA— incremental tool-argument streaming so clients can render partial JSON as the model generates it. Declared as anAiCapabilityenum value so the distinction is machine-readable on the SPI, not just prose in the matrix. OnlyBuiltInAgentRuntimeadvertises it — itsOpenAiCompatibleClientforwards everydelta.tool_calls[].function.argumentsfragment throughsession.toolCallDelta(id, chunk)on both the chat-completions and responses-API streaming paths. The six framework bridges (Spring AI, LC4j, ADK, Embabel, Koog, Semantic Kernel) cannot emit deltas without bypassing their high-level streaming APIs (895a7e0a2e); they honor the default no-op contract instead. Pinned in the Built-in contract test and inmodules/integration-tests/e2e/ai-tool-call-delta.spec.ts's negative capability assertion.AgentRuntime.models()default method returning the list of models the resolved runtime can actually serve. Replaces the configuration-intent model flag with a runtime-resolved list (Correctness Invariant #5).TokenUsagerecord(long input, long output, long cachedInput, long total, String model). Reported on completion metadata asai.tokens.input/ai.tokens.output/ai.tokens.total/ai.tokens.cachedwhen the provider surfaces it.@AiEndpoint.promptCache()and@AiEndpoint.retry()— declarative annotations on@AiEndpoint.promptCache()returnsCacheHint.CachePolicy(defaultNONE).retry()returns a nested@Retryannotation withmaxRetries,initialDelayMs,maxDelayMs,backoffMultiplier. Resolved at bean post-processing on Spring Boot and via the annotation processor at build time on Quarkus.AbstractAgentRuntimeContractTest— TCK inmodules/ai-testthat everyAgentRuntimesubclass must pass. Exercises text streaming, tool calling, tool approval, system prompt, multi-modal input, cache hint threading, execution cancel, and capability-set pinning viaexpectedCapabilities()(addedc13e309d) so adding or removing a capability from a runtime without updating its pinned set breaks the build. Drift between the code and the docs matrix intutorial/11-ai-adapters.mdcannot ship silently.
@Agent+@Command— one annotation defines the agent; slash commands routed on every wired channel (Web WebSocket plus the five external channels whenatmosphere-channelsis present). Auto-generates@AiEndpoint, A2A Agent Card, MCP tool manifest, and AG-UI event bindings based on classpath detection.atmosphere-agentmodule — annotation processor,CommandRouter,SkillFileParser,AgentHandler.skill.md— markdown files that serve as both the LLM system prompt and agent metadata (## Skills/## Tools/## Channels/## Guardrailssections parsed into Agent Card, MCP manifest, channel validation).- JetBrains Koog adapter (
atmosphere-koog). SixthAgentRuntimebacked by Koog'sAIAgent/chatAgentStrategy()with tool calling viaAtmosphereToolBridgeand cooperative cancel viaAtomicReference<Job>. - Orchestration primitives — agent handoffs
(
session.handoff(target, message)), approval gates (@RequiresApproval), conditional routing in@Fleet, and LLM-as-judge eval assertions (LlmJudge). - Samples:
spring-boot-dentist-agent,spring-boot-orchestration-demo,spring-boot-checkpoint-agent(durable HITL workflow surviving JVM restart viaSqliteCheckpointStore).
Commit hashes listed for every Fixed bullet. If there is no commit, the bullet does not belong here.
ToolApprovalPolicy.DenyAllbypass — P0 security (40d616b6ee).DenyAll.requiresApproval()previously returnedtrueand fell through to the session-scopedApprovalStrategy, so an auto-approve strategy could silently run a tool the caller intended to deny.ToolExecutionHelper.executeWithApprovalnow detectsDenyAllbefore consulting the strategy and returns{"status":"cancelled","message":"Tool execution denied by policy"}immediately. Closes Correctness Invariant #6 (fail-closed default).- Null-strategy approval bypass (
56b1046f6f). Before the DenyAll evaluation fix, a tool annotated@RequiresApprovalrunning under a context with noApprovalStrategywired would execute unguarded. NowToolExecutionHelperfails closed on null strategy; DenyAll is evaluated before the null-strategy branch. The same commit also stoppedCachingStreamingSessionfrom auto-persisting oncomplete()so a cancel-induced clean termination can no longer cache a partial response — the pipeline decides whether to commit afterruntime.executereturns. ToolApprovalPolicynot threaded through the tool-loop (b9b1af4aff). Every runtime bridge previously called the 5-argexecuteWithApprovaloverload which defaulted toToolApprovalPolicy.annotated()—context.approvalPolicy()was never consumed. All five tool-calling bridges (Built-in, Spring AI, LC4j, ADK, Koog) now call the 6-arg form and pass the policy through.ChatCompletionRequestgainedapprovalPolicyas its 13th canonical field, preserved across tool-loop rounds.tryResolvetri-state approval ID resolution (0db97e3276,c3cc904644).ApprovalRegistry.tryResolve(id)returnedtrueonUNKNOWN_ID, which causedAiPipeline/AiStreamingSession/ChannelAiBridgeto swallow stale or cross-session approval messages as if consumed. Callers now use the tri-stateresolve()method and only short-circuit onRESOLVED, lettingUNKNOWN_IDfall through to the normal pipeline.- Koog cancel race (
ae732f8301).KoogAgentRuntime.executeWithHandlepreviously relied on a soft-cancel flag polled at suspension points, so a cancel racing with a slow KoogPromptExecutorstall could leave the virtual thread hanging on a native I/O read. The runtime now captures the active coroutineJobin anAtomicReference, cancels the job, and interrupts the virtual thread as a belt-and-suspenders fallback. The same commit enables ADKContextCacheConfigbootstrap and fixes anEmbeddingRuntimeResolverstartup-order race. - LC4j premature completion + ADK model override + cross-session approval
fallback removal (
d4c11ca76a). LC4j'sdoExecutenow blocks onhandle.whenDone()before returning so the lifecycle completion fires after the tool stream actually finishes. ADK'sbuildRequestRunnernow honorscontext.model()when set instead of falling through to the module-level default.AiEndpointHandlerno longer performs a cross-session approval fallback, preserving session-ownership guarantees. - LC4j post-cancel error suppression + terminal-reason first-writer wins
(
4ca8e983d8). LC4j now dropsonErrorcallbacks that arrive after the caller cancelled (the underlying HTTP may drain an IOException out of band).ExecutionHandle.Settablenow records the first-writer terminal reason so observers can distinguish cancel from post-cancel error.RetryPolicy.isInheritSentinelformalisesDEFAULT-as-inheritance contract. ResponseCacheobservability gap + structured-output / RAG / guardrail cache-skip (28d381d4ff).CacheKeynow hashesresponseTypeso a structured-JSON request cannot replay a plain-text cached answer.AiPipelineskips the cache when context providers, guardrails, or a latently non-empty tool registry are present. The cache-hit path now firesAgentLifecycleListener.onStart+onCompletionso observability and audit traffic see a clean pair on both hit and miss paths.CacheKeyContent.File collision + tool-loop cache skip (13cf557532).CacheKeynow hashesContent.Fileparts (mime + length, later upgraded to full byte hash inc29542f1e6) so two distinct PDFs of identical length cannot collide.AiPipeline.streamTextskips the cache whencontext.tools()is non-empty so text-only replays never silently drop tool round-trips.CachingStreamingSessionbinary-sendContent poisoning (0670e2f8b3). BinaryContent(Image / Audio / File) cannot ride through a text-onlyStringBuilder, so the defaultsendContentthrow would have bypassed the text capture. Override now marks the session as errored so the pipeline's post-execute commit short-circuits — never caching a partial text-only response for a flow that emitted binary output.- Embedding runtime timeout + resolver DCL + cancel-swallow logging
(
c29542f1e6).SemanticKernelEmbeddingRuntime.block()calls inherit a 60s ceiling so a hung service cannot pin a virtual thread forever.EmbeddingRuntimeResolverwraps the slow path in a synchronized block so two early callers do not race duplicate ServiceLoader scans.ExecutionHandle.Settable.cancellogs native-cancel exceptions at TRACE instead of silently swallowing them, and documents the first-writer terminal-reason race explicitly. - Release automation stale-version patterns (
a8516e9d7c). Two gaps inscripts/update-doc-versions.shleftREADME.md"Current release" andcli/sdkman/*.mdpublish.shexamples pointing at the previous release afterrelease-4x.ymlran. Both patterns are now swept on every release. - Cross-repo docs sync on release (
dce1fba280,aadec4e1d8).release-4x.ymlnow fires arepository_dispatchevent atAtmosphere/atmosphere.github.iovia the existingSITE_DISPATCH_TOKENon successful release. A companionsync-version.ymlworkflow in the docs repo runsscripts/update-doc-versions.shand commits the result. Closes the long-standing gap where the docs site lagged the Maven Central release by days.
4.0.11 - 2026-03-11
- WebSocket XSS sanitization bypass. Disabled HTML sanitization for WebSocket transport — HTML-encoding JSON in WebSocket frames broke the AI streaming wire protocol.
- XSS and insecure cookie hardening. Sanitize HTML output in write
methods and set the
Secureflag on cookies over HTTPS.
- Token → Streaming Text rename. All AI module APIs, javadoc,
and the atmosphere.js client now use "streaming text" instead of "token"
to describe LLM output chunks. This affects method names
(
onToken→onStreamingText,totalTokens→totalStreamingTexts), field names, and the wire protocol message type ("token"→"streaming-text"). This is a breaking change for atmosphere.js consumers and customAiStreamBroadcastFilterimplementations. - Javadoc published to GitHub Pages. API docs for
atmosphere-runtimeare now deployed automatically toasync-io.org/apidocs. - Starlight tutorial site. A 20-chapter tutorial book is now available at the project documentation site.
4.0.3 - 2026-02-22
- Room Protocol broadcast bug.
DefaultRoom.broadcast()now wraps messages inRawMessageto bypass@Messagedecoder mangling. Room JSON envelopes (join/leave/message events) are delivered intact to clients. enableHistory()NPE.UUIDBroadcasterCacheis now properly configured before use, preventingNullPointerExceptionwhen room history is enabled.- Native Image build. Spring Boot samples use
process-aotandexecclassifier in thenativeprofile so GraalVM can find the main class.
RawMessageAPI (org.atmosphere.cpr.RawMessage) — first-class public wrapper for pre-encoded messages that bypass@Messagedecoder/encoder pipelines.ManagedAtmosphereHandler.Managedis deprecated in favor ofRawMessage.- Playwright E2E tests for all sample applications (chat, spring-boot-chat, embedded-jetty, quarkus-chat, AI samples, durable-sessions, MCP server).
- Unified parent POM. All samples now inherit from
atmosphere-project, makingmvn versions:setupdate every module in a single command. - Normalized artifact names. All modules use lowercase kebab-case
atmosphere-*naming consistently. - Release workflow hardened. Stale tags are cleaned before tagging, and
git rebasehandles diverged branches during release builds.
4.0.0 - 2026-02-18
Atmosphere 4.0 is a rewrite of the framework for JDK 21+ and Jakarta EE 10. It keeps the annotation-driven programming model and transport abstraction from prior versions, and adds support for virtual threads, AI/LLM streaming, rooms and presence, native image compilation, and frontend framework bindings.
This release succeeds the 2.x/3.x line (last release: 3.1.0 / 2.7.16). The
javax.servlet namespace, Java 8 runtime, and legacy application server
integrations have been removed. Applications migrating from 2.x or 3.x should
consult the Migration Guide.
- JDK 21 minimum requirement. The framework compiles with
--release 21and is tested on JDK 21, 23, and 25 in CI. - Jakarta EE 10 baseline. All Servlet, WebSocket, and CDI APIs use the
jakarta.*namespace. Servlet 6.0, WebSocket 2.1, and CDI 4.0 are the minimum supported versions. - Virtual Thread support.
ExecutorsFactorycreates virtual-thread-per-task executors by default viaExecutors.newVirtualThreadPerTaskExecutor().DefaultBroadcasterand 16 other core classes have been migrated fromsynchronizedblocks toReentrantLockto avoid virtual thread pinning. Virtual threads can be disabled withApplicationConfig.USE_VIRTUAL_THREADS=false. - GraalVM native image support. Both the Spring Boot starter and Quarkus extension include reflection and resource hints for ahead-of-time compilation. Spring Boot requires GraalVM 25+; Quarkus works with GraalVM 21+ or Mandrel.
atmosphere-spring-boot-starter-- Spring Boot 4.0 auto-configuration with annotation scanning, Spring DI bridge (SpringAtmosphereObjectFactory), Actuator health indicator (AtmosphereHealthIndicator), and GraalVM AOT runtime hints (AtmosphereRuntimeHints). Configuration viaatmosphere.*properties inapplication.yml.atmosphere-quarkus-extension(runtime + deployment) -- Quarkus 3.21+ extension with build-time Jandex annotation scanning, Arc CDI integration, customQuarkusJSR356AsyncSupport, and@BuildStep-driven native image registration. Configuration viaquarkus.atmosphere.*properties.atmosphere-ai-- AI/LLM streaming SPI. DefinesStreamingSession,StreamingSessions,AiStreamingAdapter, andAiConfigfor streaming streaming texts from any LLM provider to connected clients. Includes the@AiEndpointannotation for zero-boilerplate AI handlers and the@Promptannotation for marking prompt-handling methods that run on virtual threads automatically.atmosphere-spring-ai-- Spring AI adapter (SpringAiStreamingAdapter) that bridgesChatClientstreaming responses toStreamingSession.atmosphere-langchain4j-- LangChain4j adapter (LangChain4jStreamingAdapter,AtmosphereStreamingResponseHandler) for callback-based LLM streaming.atmosphere-embabel-- Embabel Agent Framework adapter for agentic AI with progress events.atmosphere-mcp-- Model Context Protocol (MCP) server module. Annotation-driven tools (@McpTool), resources (@McpResource), prompts (@McpPrompt), and server declaration (@McpServer). Supports WebSocket transport, Streamable HTTP transport (MCP 2025-03-26 spec), stdio bridge for Claude Desktop, and a programmaticMcpRegistryAPI.atmosphere-kotlin-- Kotlin DSL (atmosphere { ... }builder) and coroutine extensions (broadcastSuspend,writeSuspend) for idiomatic Kotlin integration. Requires Kotlin 2.1+.atmosphere-redis-- Redis clustering broadcaster using Lettuce 6.x for non-blocking pub/sub. Messages broadcast on any node are delivered to clients connected to all other nodes.atmosphere-kafka-- Kafka clustering broadcaster using the Apache Kafka client 3.x. Configurable topic prefix, consumer group, and bootstrap servers.atmosphere-durable-sessions-- Durable session SPI withDurableSessionInterceptor,SessionStoreinterface, and in-memory implementation. Sessions survive server restarts; room memberships, broadcaster subscriptions, and metadata are restored on reconnection.atmosphere-durable-sessions-sqlite-- SQLite-backedSessionStorefor single-node deployments.atmosphere-durable-sessions-redis-- Redis-backedSessionStorefor clustered deployments.atmosphere-integration-tests-- Integration test suite with embedded Jetty and Testcontainers covering WebSocket, SSE, long-polling transports, Redis and Kafka clustering, and MCP protocol compliance.
- Room API (
org.atmosphere.room).RoomManagercreates and manages named rooms backed by dedicatedBroadcasterinstances.Roomsupportsjoin,leave,broadcast, presence tracking viaonPresencecallbacks, and configurable message history replay for late joiners. - Room protocol (
org.atmosphere.room.protocol).RoomProtocolMessageis a sealed interface withJoin,Leave,Broadcast, andDirectrecord subtypes, enabling exhaustive pattern matching in Java 21 switch expressions. @RoomServiceannotation for declarative room handler registration with automaticRoomcreation viaRoomManager.VirtualRoomMemberfor adding LLM agents as room participants.- Room authorization (
RoomAuth,RoomAuthorizer) for controlling room access. RoomProtocolInterceptorfor automatic protocol message parsing and dispatching.
- Micrometer metrics (
AtmosphereMetrics). Registers gauges, counters, and timers on anAtmosphereFrameworkinstance: active connections, active broadcasters, total connections, messages broadcast, broadcast latency, room-level gauges, cache hit/miss/eviction counters, and backpressure drop/disconnect metrics. Requiresmicrometer-coreon the classpath (optional dependency). - OpenTelemetry tracing (
AtmosphereTracing). Interceptor that creates spans for every request lifecycle with attributes:atmosphere.resource.uuid,atmosphere.transport,atmosphere.action,atmosphere.broadcaster,atmosphere.room. Requiresopentelemetry-apion the classpath (optional dependency). - Health check (
AtmosphereHealth). Framework-level health snapshot reporting status, version, active connections, and broadcaster count. Integrated into the Spring Boot Actuator health endpoint viaAtmosphereHealthIndicator. - MDC interceptor (
MDCInterceptor). Setsatmosphere.uuid,atmosphere.transport, andatmosphere.broadcasterin the SLF4J MDC for structured logging.
BackpressureInterceptor-- protects against slow clients with configurable high-water mark (default 1000 pending messages) and overflow policies:drop-oldest,drop-newest, ordisconnect.
- atmosphere.js 5.0 -- TypeScript rewrite with no runtime dependencies. Ships as ESM, CJS, and IIFE bundles.
- Transport fallback -- WebSocket with configurable fallback to SSE, HTTP streaming, or long-polling. Full protocol handler with heartbeat, reconnection, and message tracking.
- React hooks --
useAtmosphere,useRoom,usePresence,useStreamingviaatmosphere.js/react. IncludesAtmosphereProviderfor connection lifecycle management. - Vue composables --
useAtmosphere,useRoom,usePresence,useStreamingviaatmosphere.js/vue. - Svelte stores --
createAtmosphereStore,createRoomStore,createPresenceStore,createStreamingStoreviaatmosphere.js/svelte. - AI streaming client --
subscribeStreamingwithonStreamingText,onProgress,onComplete, andonErrorcallbacks for real-time LLM streaming text display. - Room and presence client API -- join/leave rooms, broadcast within rooms, track online members, and display presence counts.
- Chat UI components -- shared React chat components for sample
applications via
atmosphere.js/chat.
spring-boot-chat-- Spring Boot 4 chat application with React frontend.quarkus-chat-- Quarkus 3.21+ chat application.chat-- Standalone Jetty embedded chat.embedded-jetty-websocket-chat-- Embedded Jetty with WebSocket.grpc-chat-- Standalone gRPC transport chat.spring-boot-ai-chat-- Streaming AI chat via theAgentRuntimeSPI.spring-boot-ai-tools-- Portable@AiTooltool calling across runtimes.spring-boot-ai-classroom-- Multi-room AI with a React Native / Expo client.spring-boot-rag-chat-- RAG chat withContextProvider.spring-boot-mcp-server-- MCP server with annotation-driven tools.spring-boot-durable-sessions-- Durable sessions with SQLite backend.
- Multi-JDK CI -- GitHub Actions matrix testing on JDK 21, 23, and 25.
- Native image CI -- GraalVM native builds for both Spring Boot and Quarkus with smoke tests.
- atmosphere.js CI -- TypeScript build, test, lint, and bundle size verification.
- Samples CI -- Compilation verification for all sample applications including frontend npm builds.
- Unified release workflow (
release-4x.yml) for coordinated Maven Central and npm publishing. - CodeQL analysis for automated security scanning.
- Pre-commit hooks enforcing Apache 2.0 copyright headers and conventional commit message format.
- Checkstyle and PMD enforced in the
validatephase withfailsOnError=true.
- Java 8 minimum raised to Java 21. All source compiled with
--release 21. javax.servletnamespace replaced withjakarta.servletthroughout the codebase.- Jetty 9 support replaced with Jetty 12 (
12.0.16). - Tomcat 8 support replaced with Tomcat 11 (
11.0.18). - SLF4J upgraded from 1.x to 2.0.16; Logback from 1.2.x to 1.5.18.
synchronizedblocks inDefaultBroadcaster,AtmosphereResourceImpl,AsynchronousProcessor, and 13 other core classes replaced withReentrantLockfor virtual thread compatibility.HashMapandArrayListin concurrent contexts replaced withConcurrentHashMapandCopyOnWriteArrayList.ScheduledExecutorServiceremains on platform threads for timed tasks (expected -- virtual threads do not benefit from scheduling).
instanceofchecks replaced with pattern matching throughout the codebase.if/elsechains on enums replaced with switch expressions (JDK 21).- Immutable collection factories (
List.of(),Map.of(),Set.of()) used in place ofCollections.unmodifiable*wrappers. - Lambda expressions replace anonymous inner classes where appropriate.
String.repeat()replaces manual loop concatenation.- Diamond operator applied consistently.
try-with-resourcesapplied to allAutoCloseableusage.varused for local variables where the type is obvious from context.- Records used for room protocol messages (
Join,Leave,Broadcast,Direct), cache entries, and event types. - Sealed interfaces used for
RoomProtocolMessageand related type hierarchies.
- atmosphere.js rewritten from jQuery-based JavaScript to TypeScript with zero runtime dependencies.
- Package renamed to
atmosphere.json npm, version 5.0.0. - Build tooling changed from Grunt/Bower to tsup (esbuild-based bundler) with Vitest for testing.
- Module format changed from AMD/global to ESM + CJS + IIFE triple output.
- Peer dependencies on React 18+, Vue 3.3+, and Svelte 4+ are all optional.
- TestNG retained for core
atmosphere-runtimetests. - JUnit 5 adopted for Spring Boot starter tests (via
spring-boot-starter-test). - JUnit 5 adopted for Quarkus extension tests (via
quarkus-junit5). - Mockito upgraded to 5.21.0 for JDK 25 compatibility (ByteBuddy 1.17.7).
- Integration tests use Testcontainers for Redis and Kafka.
JSR356WebSocketTestexcluded (Mockito cannot mock sealed interfaces on JDK 21+).
AtmosphereFrameworkdecomposed into focused component classes. The former 3,400-line god object is now an orchestrator (~2,260 lines) that delegates to single-responsibility components. The public API is fully preserved -- all existingframework.addAtmosphereHandler(),framework.interceptor(), etc. calls continue to work unchanged. New internal components:BroadcasterSetup-- broadcaster configuration, factory, and lifecycleClasspathScanner-- annotation scanning, handler/WebSocket auto-detectionInterceptorRegistry-- interceptor lifecycle and orderingHandlerRegistry-- handler registration and endpoint mappingWebSocketConfig-- WebSocket protocol and processor configurationFrameworkEventDispatcher-- listener management and lifecycle eventsFrameworkDiagnostics-- startup diagnostics and analytics reporting
AtmosphereHandlerWrapperfields encapsulated. Previously public mutable fields (broadcaster,interceptors,mapping) are now private with accessor methods.- Inner classes promoted to top-level.
AtmosphereHandlerWrapper,MetaServiceAction, andDefaultAtmosphereObjectFactoryare now standalone classes inorg.atmosphere.cpr.
- Legacy Maven repositories (Codehaus, maven.java.net, JBoss Nexus, Sonatype) removed. All dependencies sourced from Maven Central.
- Publishing migrated from legacy OSSRH to the Central Publishing
Portal (
central-publishing-maven-plugin). - CDDL-licensed Jersey utility classes (
UriTemplate,PathTemplate) replaced with Apache 2.0 implementations. - OSGi bundle configuration updated for
jakarta.*imports.
- Java 8, 11, and 17 support. JDK 21 is the minimum.
javax.servletnamespace. All APIs usejakarta.*.- Legacy application server support. GlassFish 3/4, Jetty 6-9, Tomcat 6-8, WebLogic, JBoss AS 7, and Netty-based transports are no longer supported. The framework targets Servlet 6.0+ containers (Jetty 12, Tomcat 11, Undertow via Quarkus).
- Deprecated APIs. Two passes of deprecated code removal
(
cf24377f0,a8e6f2be3) cleaned out dead code paths, unused configuration options, and obsolete utility classes accumulated over the 2.x/3.x lifecycle. - CDDL-licensed code. Jersey-derived
UriTemplateand related classes removed and replaced with Apache 2.0 implementations. - jQuery dependency in atmosphere.js. The client library has zero runtime dependencies.
- Netty, Play Framework, and Vert.x integrations. These have been moved to a legacy section and are no longer maintained.
- Update your JDK. Atmosphere 4.0 requires JDK 21 or later.
- Replace
javax.servletimports withjakarta.servlet. This includesHttpServletRequest,HttpServletResponse,ServletContext, and all related types. - Update your container. Use Jetty 12+, Tomcat 11+, or deploy via Spring Boot 4.0+ / Quarkus 3.21+.
- Review synchronized code. If you extended core Atmosphere classes
that used
synchronized, your subclasses may need correspondingReentrantLockupdates. - Check deprecated API usage. Methods and classes deprecated in 2.x and 3.x have been removed. Consult the Javadoc for replacements.
- Remove jQuery. atmosphere.js 5.0 has no jQuery dependency.
- Update imports. The package is now
atmosphere.json npm. Useimport { atmosphere } from 'atmosphere.js'. - Review transport configuration. The new client supports the same transports (WebSocket, SSE, long-polling, streaming) but the configuration API has been streamlined.
| Module | GroupId | ArtifactId | Version |
|---|---|---|---|
| Core runtime | org.atmosphere |
atmosphere-runtime |
4.0.0 |
| Spring Boot starter | org.atmosphere |
atmosphere-spring-boot-starter |
4.0.0 |
| Quarkus extension | org.atmosphere |
atmosphere-quarkus-extension |
4.0.0 |
| AI streaming SPI | org.atmosphere |
atmosphere-ai |
4.0.0 |
| Spring AI adapter | org.atmosphere |
atmosphere-spring-ai |
4.0.0 |
| LangChain4j adapter | org.atmosphere |
atmosphere-langchain4j |
4.0.0 |
| Embabel adapter | org.atmosphere |
atmosphere-embabel |
not yet published (pending Embabel Maven Central release) |
| MCP server | org.atmosphere |
atmosphere-mcp |
4.0.0 |
| Kotlin DSL | org.atmosphere |
atmosphere-kotlin |
4.0.0 |
| Redis clustering | org.atmosphere |
atmosphere-redis |
4.0.0 |
| Kafka clustering | org.atmosphere |
atmosphere-kafka |
4.0.0 |
| Durable sessions | org.atmosphere |
atmosphere-durable-sessions |
4.0.0 |
| Durable sessions (SQLite) | org.atmosphere |
atmosphere-durable-sessions-sqlite |
4.0.0 |
| Durable sessions (Redis) | org.atmosphere |
atmosphere-durable-sessions-redis |
4.0.0 |
| TypeScript client | atmosphere.js (npm) |
atmosphere.js |
5.0.0 |
| Dependency | Minimum Version | Tested Up To |
|---|---|---|
| JDK | 21 | 25 |
| Servlet API | 6.0 (Jakarta EE 10) | 6.1 |
| Spring Boot | 4.0.5 | 4.0.5 |
| Spring Framework | 6.2.8 | 6.2.8 |
| Quarkus | 3.21 | 3.31.3 |
| Jetty | 12.0 | 12.0.16 |
| Tomcat | 11.0 | 11.0.18 |
| Kotlin | 2.1 | 2.1+ |
| GraalVM (Spring Boot) | 25 | 25 |
| GraalVM / Mandrel (Quarkus) | 21 | 25 |
For changes in the 2.x and 3.x release lines, see the
GitHub Releases page
and the atmosphere-2.6.x branch.