Session state: who is connected, when they last spoke, and the conversational state that belongs to one dialogue rather than to the JVM — the sticky namespace, the told-once ledger's audience, the tool-list fetch marker, queued eviction news (§11).
Streamable HTTP sessions are server-minted: initialize gets an id in
the Mcp-Session-Id response header and the client echoes it on every
subsequent request (measured 2026-08-04, claude-code 2.1.220). Sessions
are cheap and ephemeral — a reconnect abandons the old one without the
spec's DELETE goodbye (measured the same day) — so everything here
expires by silence, and an id never seen before is adopted rather than
404'd: after a server restart the client keeps presenting its old id,
and forcing a re-initialize would buy spec strictness at the price of
churn. A deliberate deviation, recorded in §11.
State lives behind defonce for the same reason the registry's does:
library reloads must not end anyone's session.
Session state: who is connected, when they last spoke, and the conversational state that belongs to one dialogue rather than to the JVM — the sticky namespace, the told-once ledger's audience, the tool-list fetch marker, queued eviction news (§11). Streamable HTTP sessions are server-minted: `initialize` gets an id in the `Mcp-Session-Id` response header and the client echoes it on every subsequent request (measured 2026-08-04, claude-code 2.1.220). Sessions are cheap and ephemeral — a reconnect abandons the old one without the spec's DELETE goodbye (measured the same day) — so everything here expires by silence, and an id never seen before is adopted rather than 404'd: after a server restart the client keeps presenting its old id, and forcing a re-initialize would buy spec strictness at the price of churn. A deliberate deviation, recorded in §11. State lives behind `defonce` for the same reason the registry's does: library reloads must not end anyone's session.
The session an eval runs for — bound by evaluate on both attribution
rails exactly as tee/*bank* is (§11), so code like (evals) can tell
the caller's entries from another session's. nil at the root means a
sessionless in-process caller — a human at the actual REPL calling api
functions directly; the transport never admits one (bare requests are
400'd, 2026-08-06).
The session an eval runs for — bound by `evaluate` on both attribution rails exactly as `tee/*bank*` is (§11), so code like `(evals)` can tell the caller's entries from another session's. nil at the root means a sessionless in-process caller — a human at the actual REPL calling api functions directly; the transport never admits one (bare requests are 400'd, 2026-08-06).
(clear-evictions! sid ids)Called only once the response carrying the news has actually gone out — the same discipline as every delivery mark (§5).
Called only once the response carrying the news has actually gone out — the same discipline as every delivery mark (§5).
(client sid)(client! sid m)What initialize said about the caller — protocol version, client name
and version, capabilities. Kept per session because clients keep
teaching us their actual shape (§4), and knowing which client and
version a measurement was made against keeps the measurements honest.
What `initialize` said about the caller — protocol version, client name and version, capabilities. Kept per session because clients keep teaching us their actual shape (§4), and knowing which client and version a measurement was made against keeps the measurements honest.
(current-ns sid)(current-ns! sid ns-sym)Where sid's last eval ended — the sticky namespace is conversational
state, so it lives and dies with the session; a reconnect starts back
at scratch (§11).
Where `sid`'s last eval ended — the sticky namespace is conversational state, so it lives and dies with the session; a reconnect starts back at scratch (§11).
(drop! sid)Forget sid. The registry releases a session's entry claims before
dropping it — see registry/release-session!, which owns that order.
The session's scratch namespace goes with it — conversational state
dies with the session — so an eval somehow still running there fails
loudly at its next form (No namespace) rather than working on in a
ghost. The sessionless in-process caller's shared scratch is never
removed — no session to die with.
Forget `sid`. The registry releases a session's entry claims before dropping it — see `registry/release-session!`, which owns that order. The session's scratch namespace goes with it — conversational state dies with the session — so an eval somehow still running there fails loudly at its next form (`No namespace`) rather than working on in a ghost. The sessionless in-process caller's shared scratch is never removed — no session to die with.
(expired)Session ids whose silence has outlasted expiry-ms. Open streams keep
their session fresh — every successful heartbeat write refreshes the
stamp — so a session mid-await cannot expire under it (§11). A stampless
entry counts as ancient: it can only arise from a write racing a drop,
and releasing it again is harmless.
Session ids whose silence has outlasted `expiry-ms`. Open streams keep their session fresh — every successful heartbeat write refreshes the stamp — so a session mid-await cannot expire under it (§11). A stampless entry counts as ancient: it can only arise from a write racing a drop, and releasing it again is harmless.
How long a session may stay silent before it is presumed gone and its
claims released. Deliberately the await clamp's own value — mcp derefs
this var for it, so the two cannot drift: any wait the protocol will
grant, the session survives to collect. Generous over stingy until
proven insufficient (2026-08-04); the cost is bounded — a dead session's
unread entries ride above the capacity for at most a day.
How long a session may stay silent before it is presumed gone and its claims released. Deliberately the await clamp's own value — `mcp` derefs this var for it, so the two cannot drift: any wait the protocol will grant, the session survives to collect. Generous over stingy until proven insufficient (2026-08-04); the cost is bounded — a dead session's unread entries ride above the capacity for at most a day.
(fetched-tools sid)(fetched-tools! sid decls)The tool declarations as sid last actually fetched them. Per session,
for the same reason the marker exists at all (§4): a lost announcement
re-announces on the next stream, and each client's cache is its own.
The tool declarations as `sid` last actually fetched them. Per session, for the same reason the marker exists at all (§4): a lost announcement re-announces on the next stream, and each client's cache is its own.
(live-count)How many sessions are current — the n of the capacity formula (§11).
Counted after the reap that precedes every admission, so the dead never
inflate the pool.
How many sessions are current — the `n` of the capacity formula (§11). Counted after the reap that precedes every admission, so the dead never inflate the pool.
(manual-read! sid)Mark sid as having read the manual — set when api/manual runs on its
rails. Until it is set, eval responses carry a one-line unread note (§4):
the keys stay in the model's hands, but ignorance doesn't stay silent.
Doubles as the compliance measurement the lean-instructions design is
smoke-tested by. Guarded like note! — a dead sid is not recreated —
which also makes the sessionless in-process caller a no-op.
Mark `sid` as having read the manual — set when `api/manual` runs on its rails. Until it is set, eval responses carry a one-line unread note (§4): the keys stay in the model's hands, but ignorance doesn't stay silent. Doubles as the compliance measurement the lean-instructions design is smoke-tested by. Guarded like `note!` — a dead sid is not recreated — which also makes the sessionless in-process caller a no-op.
(manual-read? sid)(mint!)A fresh session, born now. The transport puts the id in the initialize
response's Mcp-Session-Id header; the client echoes it thereafter.
A fresh session, born now. The transport puts the id in the `initialize` response's `Mcp-Session-Id` header; the client echoes it thereafter.
(note! sid s)A self-description for the roster — what this session is for, in its own words (§11). Conversational state like everything here: it dies with the session, which is right, because so does the purpose.
A self-description for the roster — what this session is for, in its own words (§11). Conversational state like everything here: it dies with the session, which is right, because so does the purpose.
(note-evictions! sid ids)Queue eviction news for sid: its entries went under another session's
admission, and an id that silently stops resolving is §5's nasty failure
mode regardless of whose admission did it. Drained into the owner's next
response. A sid no longer live is not recreated — its reader is gone.
Queue eviction news for `sid`: its entries went under another session's admission, and an id that silently stops resolving is §5's nasty failure mode regardless of whose admission did it. Drained into the owner's next response. A sid no longer live is not recreated — its reader is gone.
(pending-evictions sid)(roster)Every live session as data — id, last-seen, client info, note — for the
API layer's sessions listing, which adds what only other namespaces
know (entry counts, who is asking).
Every live session as data — id, last-seen, client info, note — for the API layer's `sessions` listing, which adds what only other namespaces know (entry counts, who is asking).
(scratch-ns-sym sid)The scratch namespace sid's evals start in. Per session, so two
tenants' defs and requires cannot collide — named by the same 8-char id
prefix :by attribution wears, s-prefixed into a legal symbol
segment and filtered to what a symbol can carry, since an adopted sid
is client-chosen text (hashed whole when nothing survives the filter).
nil — the sessionless in-process caller, never the wire — keeps the
shared scratch: no session to die with, nothing to reap.
The scratch namespace `sid`'s evals start in. Per session, so two tenants' defs and requires cannot collide — named by the same 8-char id prefix `:by` attribution wears, `s`-prefixed into a legal symbol segment and filtered to what a symbol can carry, since an adopted sid is client-chosen text (hashed whole when nothing survives the filter). nil — the sessionless in-process caller, never the wire — keeps the shared scratch: no session to die with, nothing to reap.
(seen! sid)Refresh sid's last-seen stamp, adopting an unknown id — a restarted
server's returning client presents an id minted before the restart.
Returns sid so establishing a session reads as one expression.
Refresh `sid`'s last-seen stamp, adopting an unknown id — a restarted server's returning client presents an id minted before the restart. Returns `sid` so establishing a session reads as one expression.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |