Skip to content

Releases: kmetia/kmet-agent

v0.2.0

Choose a tag to compare

@markokocic markokocic released this 21 Oct 09:11

v0.2.0 — the JVM Clojure host

kmet now runs on three hosts: Babashka (the primary one), native Jolt, and
JVM Clojure. Same source tree, same features, same extensions — plus a
platform-independent release artifact, a JVM test gate, and a JVM nREPL for
development. kmet --version in a source checkout reports the real version
again, and the model catalogs are refreshed.

JVM Clojure host

bb start-jvm                                  # run the app under JVM Clojure
bb nrepl-jvm [port]                           # nREPL on the JVM classpath (default 7803)
bb test-jvm / bb test-ext-jvm                 # the full gate, on the JVM
bb test-changed-jvm / bb test-ext-changed-jvm # the changed-file loop, on the JVM
bb uberjar-jvm                                # target/uberjar-jvm.jar (java -jar …)
bb dist-jvm                                   # dist/kmetc-<version>-jvm.zip

Running from a checkout needs the Clojure CLI;
the packaged artifact just needs a Java runtime (verified on JDK 21 and 25).

  • A third host, named. Host detection learned the JVM: the welcome logo
    reads kmet (clojure) and the footer badge is now Кц beside Кб
    (Babashka) and Кј (Jolt) — the Cyrillic transliteration of each runtime's
    initial.
  • kmetc, so all three install side by side. The JVM's command is kmetc
    (Babashka keeps kmet, Jolt keeps kmetj). Its artifact is one uberjar plus
    launchers — kmetc.jar with kmetc, kmetc.sh, kmetc.bat, kmetc.cmd
    and kmetc.ps1, all honouring KMET_JAVA_OPTS — so one zip serves every
    platform with no cross-building. The jar is AOT-compiled behind the
    kmet.agent.jvm-main :gen-class entry, carries the model catalogs, the
    bundled extensions and a baked version, and every build ends with a smoke test
    (--version and --list-models) so a jar that assembles but cannot start
    fails the build.
  • Extensions work the same way. Extension :deps resolve in-process through
    tools.deps on this host (:jvm alias), and the bundled extensions are
    staged under the same resource keys on every artifact, so an extension loads
    from the same path on all three hosts. Clojure is pinned once (:clj-pin,
    1.12.5) and the dev run, the test tasks and the packager all resolve through
    it, so they cannot drift apart.
  • The clipboard works on Windows. org.babashka/ffi — the standalone
    extraction of Babashka's babashka.ffi — is now a JVM dependency, so
    kmet.libs.clipboard-win is no longer Babashka/Jolt-only. It needs the
    Class-File/FFM API of JDK 22+: the :jvm alias grants native access and the
    jar repeats the grant as an Enable-Native-Access manifest attribute, so
    java -jar needs no flag. An older JVM still runs the app and falls back to
    the platform tools.
  • JVM-only gaps closed. SCI evaluation and output binding in run_code,
    extension ui-custom components, and kmet.tui.core's protocol re-export
    snapshots now behave on the JVM as they do on Babashka.
  • Dev nREPL ports are split per host: 7801 (bb nrepl), 7802 (Jolt's
    nrepl-server), 7803 (bb nrepl-jvm, writes .nrepl-port). The clojure
    extension's port discovery probes 7801–7803 before the historical
    7888/1667 fallbacks.

Downloads

Host Artifact Run as Needs
Babashka kmet-<version>-<platform>.zip kmet nothing
Jolt kmetj-<version>-<platform>-static.zip / …-dynamic.zip kmetj native libs only for dynamic
JVM kmetc-<version>-jvm.zip kmetc a Java runtime

Jolt zips now name their native link mode (-static / -dynamic, -dev
for dev builds): a static build is self-contained while a dynamic one needs its
native libraries on the host, so a release can carry both and tell them apart.
The executable stays kmetj — static and dynamic are two builds of one command.

Runtime and extensions

  • One owned app tree. Every registry — tools, commands, hooks, skills,
    prompt templates, renderers, transformers, flags, process stores — is mounted
    on the app root and owned per registration. The root mounts before extensions
    load and remounts on /reload.
  • Unloading disposes everything. An extension's shutdown is followed by a
    disposal pass over everything it registered and the resources it loaded,
    contributed themes included — no leftovers after /reload or a runtime
    unload.
  • New /units command. Lists registrations: every store owner (a
    registry's address, an extension's registrations) with its keys, one flat line
    each. It is engine-portable, so RPC clients get it too.
  • One ordered event bus. A single process-level registry with node-scoped
    subscriptions: handlers run in registration order, and a node that is torn
    down stops receiving.
  • /compact mid-turn is deferred instead of dropped. Running it while the
    agent works now queues the compaction and starts it when the turn settles;
    the RPC compact command answers {:accepted true :scheduled true}, the
    extension :compact capability reports through the caller's callbacks, and
    session swaps or /new drop pending requests.

Fixes

  • Stealth models after a /model switch. CommandCode's stealth endpoints
    reject an assistant message with no reasoning_content (an empty string
    included), so every request after a mid-session switch to
    stealth/cat-jam:free or reflection/beam:free failed with a 400. Those
    models now get the non-empty reasoning placeholder they require.
  • run_code and clojure_eval call lines show the code. The tool call line
    is the code itself (quiet mode shows the first non-blank line instead of a
    bare prompt), and a script starting with a blank line no longer leaves an
    empty line above the call.
  • --version in a source checkout reported dev on every host; it reports
    the real version again.
  • Extension :terminate survives a scripted run_code call and a hook that
    blocks a call, instead of being dropped.

Models

  • Model catalogs refreshed: new deepseek-v4.1-flash-1017, minimax-m3.1 and
    step-5-preview entries, provider catalog updates (Bedrock, Cloudflare,
    Hugging Face, OpenRouter, Qwen, xAI and more), and opencode's space-bunny
    retired.

Under the hood

  • The agent loop is split out of one namespace into
    kmet.agent.loop.{state,message,compact,completion}, and the composition
    runtime shrank to the store (kmet.libs.scope) and the node/stage mounting
    in kmet.agent.runtime.
  • Module coordinates are renamed kmetia/* → kmet/*; the Babashka uberjar
    payload is now target/uberjar-bb.jar, distinct from the JVM jar.
  • README and user docs describe the three hosts, their artifacts and their
    tasks.

Full changelog: v0.1.3...v0.2.0

v0.1.3

Choose a tag to compare

@markokocic markokocic released this 17 Oct 19:40

v0.1.3 — 2026-10-17

219 commits since v0.1.2.

Highlights

  • RPC mode — a headless front end for editors and scripts. kmet --mode rpc
    serves a session over EDN on stdin/stdout: one command per line, responses
    correlated by an optional :id, events streaming in print mode's wire
    projection. Clients prompt, steer, follow up, abort, clear queues,
    open/switch/fork/clone sessions, read messages/entries/tree/stats, export
    HTML, set model and thinking level, set the queue modes, compact, and list
    commands. Extension dialogs arrive as :ui-request records and are answered
    with {:type :respond ...} (a timeout resolves the request's degraded
    default); notify/status/widget/title/editor channels are fire-and-forget. A
    thin client library (kmet.modes.rpc-client), a real subprocess
    end-to-end suite, and docs/rpc.md (with the pi parity
    table) ship with it.
  • Print mode resumes sessions and can speak EDN. -c/--continue and
    --session <id|prefix|path> now work under --print, through the same
    resolver the TUI uses; print sessions land in the cwd-encoded session dir,
    so a print run can be continued later, and a resumed session keeps its
    recorded working directory. --mode edn (implies --print) writes the
    session header plus one EDN map per event, :message-update deltas only,
    with exception payloads stringified so the stream stays readable. Print
    consumes the runtime's event stream and settles from :agent-settled, so
    aborted and failed runs report to stderr and exit non-zero.
  • Packages can come from git. kmet install git:host/path[@ref] (protocol
    URLs and scp-like forms work too) clones into a managed checkout under the
    scope's git/ root, records the source verbatim, and validates the ref so a
    crafted one cannot smuggle a git option. //subdir names a package inside a
    repository — several packages share one clone, each with its own settings
    entry, identity, filters and config row. kmet update [source] fetches and
    hard-resets (a pinned source to its ref, an unpinned one to the origin's
    default branch); kmet remove deletes the checkout along with the last
    entry that uses it.
  • A Tk GUI backend over an extracted, toolkit-agnostic hiccup engine. The
    hiccup core moved out of kmet.tui into kmet.libs.hikap (.core,
    .component, .alias) and reakt into kmet.libs.reakt.core, both
    parameterized for other toolkits; the new kmet.tk.* backend renders the
    same trees into Tk on both babashka and Jolt, with Tcl 9.1/9.0/8.6
    loading, Tk paired to the interpreter's ABI, the classic (:tk/…) and
    themed (:ttk/…) widget sets, an image layer, canvas items, context menus,
    treeviews, grid/place, native dialogs, editable text, multiple windows and
    the TUI theme as a dark ttk style set. App UI over it (:ui/… tags,
    kmet.agent.ui.gui.transcript) and two demos
    (bb scripts/demos/gui_tk_demo.clj,
    bb scripts/demos/gui_tk_session.clj) land too; it is not yet wired to a
    CLI launch mode.
  • The source tree is now a workspace of modules. Application code lives
    under modules/ (agent, ai, libs, tui, loader, tk, reakt,
    hikap), each a standalone classpath root, and modules.edn is the single
    workspace manifest every task reads — the test registry is derived from the
    tree instead of hand-maintained, and guards hold the literal bb.edn/
    deps.edn lists to it. modules/app became modules/agent and the app
    namespaces flattened under kmet.agent.
  • The session runtime is the front-end API. kmet.agent.session-runtime
    owns the wiring (agent state, system prompt, config-derived run options,
    extension handle) and exposes prompt!/steer!/follow-up!/cancel!/
    compact! plus a subscriber list with per-subscriber error isolation, so
    the TUI, print, and RPC are all just subscribers; a layer guard now fails
    any mode or UI namespace that reaches into the agent loop directly.
  • Registries are engine-scoped. Commands (with a pending buffer and no
    fallback reads), custom tools and tool sources, extension event listeners,
    input/before-agent-start hooks, tool-call/tool-result hooks, and markdown
    transformers plus entry/message renderers are owned by the engine that
    registered them — the ground work for multi-engine sessions.
  • Faster markdown and wrap paths. md/parse on a 2 KB message drops
    1408 → 278 µs (bb) / 1144 → 397 µs (jolt); a 17 KB prose line 27.2 →
    1.64 ms (bb); perf.md 148.6 → 60.2 ms (bb). The wrap tracker and
    truncate-to-width run the hand-rolled ANSI scanners on both hosts
    (styled tracker line 40.5 → 4.2 µs jolt; a 300-char styled line truncated
    to 100 columns 1630 → 93 µs jolt, 17.5×), and the bash/output sanitizers
    share the scanner and skip the CR passes when there is no CR.
  • Newer models. Batch-priced entries across Anthropic, OpenAI, Google,
    xAI and Qwen on Bedrock, Vertex and the gateways; Claude Fable 5/5.1,
    Gemini 4 Argon, GPT-6.1 Sol, Muse Spark Open / Muse Wonder, Nemotron 3.5
    Super VL, LFM2.5-24B-A2B, GLM-5.3-Flash Free and more on OpenRouter;
    Together's catalog grows (Kimi K2.6 default, MiniMax M2.7/M3). The
    opencode-go default moves to deepseek-v4.1-flash (upstream retired
    deepseek-v4-flash); several dead OpenRouter entries (Claude Opus 4,
    Claude 3 Haiku, free previews) are dropped.

Upgrade notes

  • Jolt floor is v0.8.22 (was v0.8.21). Several workarounds for now-fixed
    Jolt issues are retired early, and self-contained builds carry the new
    reakt and hikap modules.
  • Source layout moved: src/kmet/… → modules/<module>/src/kmet/…, and
    the app namespace root is kmet.agent (kmet.app.* is gone). Extension
    authors should follow the header docs; kmet.extension is now
    kmet.agent.extension, kmet.tui.hiccup is kmet.tui.hikap, and the
    extracted libraries are kmet.libs.hikap.core / kmet.libs.reakt.core.
  • opencode-go's default model is deepseek-v4.1-flash. If your
    settings.edn pins "deepseek-v4-flash", update it — the old id no longer
    resolves.
  • --mode now selects the non-interactive mode: text (print output,
    the default), edn, or rpc. A valid --mode without -p still runs
    non-interactively, and an invalid one exits 1.
  • Packages: local sources behave as before; git checkouts are managed
    under ~/.kmet/agent/git (.kmet/git with -l) and are never edited by
    hand — kmet update is the way to move one. A configured git package that
    is not installed (or whose subdirectory is gone) is skipped with a warning
    at load. npm sources and pi's --self/--models remain unported; bare
    kmet update is the all-packages form.
  • Headless safety is enforced: a guard walks the static require graph of
    print and RPC and fails if either reaches the TUI, the app UI, or the Tk
    backend (kmet.tui.theme stays reachable through the extension ABI).

RPC mode

  • kmet.modes.rpc serves EDN commands on stdin and protocol records on
    stdout; a malformed line answers a parse response without an id, and a
    handler throw is that command's failure response — never the process's.
    Stdin EOF disposes the engine.
  • Prompting: prompt (pi's disposition rules), steer, follow-up,
    abort, clear-queue, new-session, get-state. A prompt while a run is
    active requires :streaming-behavior (:steer or :follow-up); steer and
    follow-up reject :images instead of dropping them silently.
  • Session: get_messages, get_last_assistant_text, get_session_stats,
    export_html, switch_session, fork, clone, get_entries, get_tree,
    set_session_name. Model: set_model, cycle_model,
    get_available_models. Thinking: set_thinking_level,
    cycle_thinking_level, get_available_thinking_levels. Queue modes and
    compaction: set_steering_mode, set_follow_up_mode, compact,
    set_auto_compaction. Discovery: get_commands, filtered to :rpc and
    source-tagged :extension/:builtin/:prompt/:skill.
  • The extension UI port forwards dialogs per front end with per-kind degraded
    defaults, and a single-line /<name> dispatches through the same command
    registry the TUI uses — portable builtins and extension commands answer
    :handled (extension commands execute immediately, even mid-stream), while
    unknown slash text stays an ordinary prompt.
  • kmet.modes.rpc-client is the scripted client (start/stop!, send!,
    request!, on-event!, on-settle!, wait-idle!, stderr and unparsed
    lines), exercised by a ^:slow suite that drives a real subprocess.

Print mode

  • Shared session resolution: path-like args against cwd, otherwise an exact
    id then an id prefix under the sessions base dir; an unmatched argument
    reports to stderr and exits 1; --session wins over --continue.
    -r/--resume stays TUI-only.
  • --mode edn emits the session header and every event as one EDN map per
    line through event-bus/wire-event, which drops the cumulative assistant
    snapshot from :message-update and stringifies error slots so a Throwable
    never breaks a consumer.
  • The run's completion and exit code come from :agent-settled; a throw in
    the consumer delivers the failure before rethrowing, so the result promise
    can no longer be left undelivered.

Packages

  • kmet install accepts git:host/path[@ref], #ref, https://, ssh://,
    git:// and scp-like forms; refs are validated against option injection.
  • //subdir (directory or single file) makes a monorepo contribute several
    independent packages over one checkout; a missing subdirectory fails before
    anything is persisted, listing the checkout's directories, and a checkout
    cloned solely for the failed install is removed again.
  • `kmet u...
Read more

v0.1.2

Choose a tag to compare

@markokocic markokocic released this 12 Oct 10:55

v0.1.2 — 2026-10-12

150 commits since v0.1.1.

Highlights

  • The run lifecycle now tracks pi end to end. The two remaining boundaries
    — :turn-end and :agent-before-settle — are actionable: a handler returns
    session :entries and :continue true to extend the run, and :turn-end
    hands over the persisted entry ids. A message queued from :agent-end runs
    as a fresh attempt in the same prompt. A custom message sent while streaming
    is held in a real pending queue until the turn's tool results are in, so it
    can no longer land between a tool call and its result.
  • Append-only per-message context edits. A {:role :context-edit ...}
    entry omits or rewrites an earlier message for every future provider
    request, while the raw session (usage totals, replay, the TUI) keeps the
    original.
  • Compaction reliability. Summarization calls retry and report their
    cause; the summary cap gains the session's thinking budget, so a
    deep-thinking model no longer truncates (and fails) a summary; per-model
    budgets land as :compact-model-overrides; :session-before-compact can
    cancel or supply the summary itself; a throwing summarizer ends compaction
    cleanly.
  • A stalled provider can no longer hang a turn. The stream idle timeout is
    120 s by default (was 300 s), the total request deadline is off by default,
    and the wait for the response to start shares the idle deadline — a request
    the provider accepts but never answers fails instead of leaving the spinner
    running. Print mode honors the configured timeouts too.
  • Memory is reclaimed again. New kmet.libs.weak: track! component
    watches and reaction dependency watches are held weakly and swept, the
    component drop sites dispose, and --debug prints a one-line
    leak-survivor report after teardown.
  • Frames got cheaper and the spinner quieter. The spinner paints half as
    many frames at the same revolution speed, bucket-paced drivers skip a wake
    when a frame is already fresh, unchanged lines and whole passes are reused,
    and the frame's cursor/normalize/diff walks are fused. Steady frames run at
    ~14 ms (bb) / ~12.5 ms (jolt) on a 2.6 MB transcript.
  • Windows and Jolt. The powershell tool ships as a bundled opt-in
    extension; session writes survive a Windows AV lock; path completion
    understands drive and UNC paths. Jolt's floor moves to v0.8.21 and
    jolt dist now defaults to the optimized fast-boot build.
  • Newer models. Claude Haiku 5.5 across Anthropic, Copilot, Bedrock, the
    gateways and OpenRouter; Mistral Large 4, Codestral 25.08 and the Ministral
    3 family; GPT-6.1 Sol/Pro batch entries; Nano Banana 2 Lite on Vertex.

Upgrade notes

  • run_code is emit-only. (emit value) (or sandbox/emit) is the single
    reported channel; stdout, stderr and the script's final value are captured
    for the output budget but never reported. A script that printed or returned
    its result must emit it.
  • HTTP defaults changed: :http-idle-timeout-ms 300000 → 120000,
    :http-total-timeout-ms nil (follow idle) → 0 (disabled). The idle timeout
    now also bounds the response-start wait. Set both explicitly to keep the old
    behavior.
  • Follow-up messages drain one at a time by default (:follow-up-mode
    :all → :one-at-a-time); :steering-mode still defaults to :all.
  • /thinking <level> now persists the level as the session default, not
    just the session's current value.
  • New :default-tools setting selects the built-in tools: plain names
    replace the set, +name/-name modify it, unset means all; extension tools
    are unaffected. The config TUI now edits it and starts in project scope when
    the project has a .kmet/ dir.
  • jolt dist builds the optimized image by default (--opt); --release
    produces the old backtrace-carrying binary and --dev stays unoptimized.
    The Jolt floor is v0.8.21 (was v0.8.16).
  • bb slop scans source only by default; --test includes tests.

Sessions and the agent loop

  • :turn-end fires after every turn — including an errored or aborted
    response, where it precedes :agent-end — with the boundary state
    (:context-entries/:context-messages, the projection-aware
    :llm-messages, :pending-messages, :can-continue) plus
    :message-entry-id and :tool-result-entry-ids. Returned :entries are
    appended in order ({:role :custom} is extension state; {:role :custom-message} also enters the context) and :continue true runs one
    more turn once the entries are committed and the context can back it
    (dropped with a warning otherwise). Handlers on the same boundary see each
    other's :entries/:continue merged.
  • :agent-before-settle fires once before the prompt settles, carrying the
    same boundary state and the same return contract.
  • A message an :agent-end handler queues (via send-user-message or
    send-message! with :trigger-turn) drains into a fresh attempt in the
    same prompt; a second batch still queued is picked up by that attempt's own
    poll. A send from :agent-settled stays queued for the next submission,
    and cancelling clears the queues and ends the continuation.
  • Pending custom-message queue and :next-turn (pi: _pendingCustomMessages
    / _pendingNextTurnMessages): a message deferred while streaming is
    appended once the turn's tool results are in, at every turn end and at the
    settle boundary.
  • Append-only context edits: {:role :context-edit :target-id <entry-id> :replacement nil | {:content ...}} omits or rewrites that earlier message
    for future requests (a rewritten tool result keeps its call id, so the
    call/result pairing survives). Only editable message roles on the active
    branch are targetable; the projection changes, the session does not.
    kmet.app.loop/append-context-edit! is the same operation outside a
    boundary handler.
  • The post-run threshold compaction check runs from the settle path in both
    the :settled and :error arms, after the attempt's :agent-end; a
    threshold compaction never retries the turn.
  • Tool calls outside the active set are rejected as Tool <name> not found
    (pi: prepareToolCall) instead of executing via registry lookup — a
    disabled built-in or a hallucinated name can no longer run.
  • agent-end reports the run's accumulated messages (pi: newMessages) and
    re-bases when a mid-run compaction or :context replacement swaps the
    context, fixing a stale subvec that settled completed turns as errors.
  • An abandoned attempt is omitted from the recovery context before the retry
    backoff and overflow compaction; session switches recreate the runtime
    selection from settings, as pi does.
  • Compaction and branch summaries: a successful compaction emits
    :session-compact with the appended rollup entry, :from-extension,
    :reason and :will-retry; the summarizer's error cause is carried through
    instead of collapsed; retries are observable through
    :summarization-retry-scheduled / :summarization-retry-attempt-start /
    :summarization-retry-finished.
  • A cancelled summarization that had not started now returns {:aborted true}
    instead of racing a spurious "No API key" error.

Compaction and tokens

  • The summarization output cap is 0.8 × the effective reserve plus the
    session level's thinking budget when the model reasons, bounded by the
    model's max output (pi: adjustMaxTokensForThinking) — a deep-thinking
    session no longer spends its whole allowance on reasoning and gets its
    summary rejected as length-truncated.
  • :compact-model-overrides, keyed by the exact "provider/modelId", tunes
    :reserve-tokens/:keep-recent-tokens per model with per-field fallback to
    the ordinary setting (pi: compaction.modelOverrides) — a 1M-window model
    can reserve room for its responses without changing every other model.
  • :session-before-compact may return {:cancel true} or supply the summary
    itself with {:compaction {...}} (the entry then records :from-hook and
    the events carry :from-extension); its payload gains
    :custom-instructions, :will-retry and a projection-aware
    :preparation.

HTTP and providers

  • The response-start wait is bounded by the idle timeout (pi: undici
    headersTimeout = httpIdleTimeoutMs), so a provider that accepts the
    request but never responds fails retryably instead of waiting forever.
  • Idle default 120 s; total deadline disabled by default, nil tracks idle,
    a positive value sets an independent deadline. Print mode builds its agent
    with the configured timeout values (it previously let the defaults win
    silently).
  • SSE stream chunks are handed off as batches instead of single bytes,
    cutting per-chunk overhead on hot streams.
  • The Anthropic, Google and Vertex request builders now report payload
    conversion and auth-token failures through the caller's promise instead of
    capturing them in an undereferenced future (which left the turn hanging).
  • A stored opencode-go credential no longer overrides an explicit settings
    :provider; only KMET_PROVIDER does. The dead stealth/space-bunny-alpha
    canonical ref is gone.
  • New end-to-end coverage for the google-generative-ai stream path.

Tools

  • run_code runs scripts on a full babashka surface: the sandbox copies the
    host's loaded clojure.*/babashka.* namespaces (macros survive) and
    babashka's class table, so clojure.pprint, java.io.*, System,
    Throwable and future resolve as in a babashka script; the fixed bundled
    extension set (rewrite-clj.*, cljfmt.*, edamame.core,
    parinferish.core) is available in-process. kmet's own namespaces stay
    blocked. Output is emit-only (see Upgrade notes); Jolt keeps its smaller
    class surface.
  • pi's powershell to...
Read more

v0.1.1

Choose a tag to compare

@markokocic markokocic released this 05 Oct 15:44

v0.1.1 — 2026-10-05

164 commits since v0.1.0.

Highlights

  • MCP servers on both protocol eras. The mcp-adapter now speaks the
    stateless 2026-07-28 revision over streamable HTTP and stdio (discovery
    probe, resultType results, long-lived subscriptions/listen catalog
    streams, x-mcp-header parameter mirroring) while keeping the legacy
    2025-11-25 handshake and the deprecated HTTP+SSE transport working. The
    negotiated era is cached and re-probed when a server contradicts the hint.
  • Streamed session resume. The resume selector lists sessions
    newest-first and fills rows as each file finishes, so a recent session is
    selectable immediately instead of after the full scan. Closing or picking
    a session stops the remaining work.
  • Ctrl+Z suspends kmet to the background on Unix; fg restores the
    terminal and the TUI. On Windows the chord reports the unsupported status.
  • clojure_eval joins the Clojure extension: evaluate code in a running
    nREPL server, discovering the port from port files or by probing the
    common ports.
  • Newer models. GPT-6 Sol and GPT-6 Luna are available and the Codex
    provider now defaults to GPT-6.1 Sol.

Upgrade notes

  • Dev commands were renamed: bb run → bb start, and jolt run -m kmet.core → jolt start.
  • The built-in script tool is now run_code (tool name, namespace, UI
    label, session vocabulary, and :run-code/* errors all follow). Any
    extension or mode config referencing script must be updated.
  • The Babashka floor is now 1.13.225.
  • Jolt's minimum version now tracks the latest tagged Jolt release
    (:jolt/min-version in deps.edn).
  • clojure.data.xml is no longer in the shared host set; an extension
    needing it declares a Maven dependency.

MCP servers (mcp-adapter)

  • Modern 2026-07-28 support over streamable HTTP and stdio: server/discover
    probing, MCP-Protocol-Version/Mcp-Method/Mcp-Name headers, per-connection
    subscriptions/listen, x-mcp-header parameters mirrored into Mcp-Param-*
    headers, and spec-invalid tool definitions dropped from tools/list.
  • Legacy revisions 2025-11-25, 2025-06-18, 2025-03-26, and 2024-11-05
    via the initialize handshake, with the negotiated revision carried on
    later requests; the deprecated HTTP+SSE binding stays supported for
    handshake-era servers with spec-correct SSE framing and no endpoint polling.
  • Authentication hardening: RFC 9728 protected-resource metadata and RFC 8707
    resource indicators, RFC 9207 issuer validation, DCR application_type,
    issuer-keyed credential store (v2 file migration; refresh never crosses
    authorization servers), callback-redirect and authorization-state
    validation, and hardened credential-store file/process handling.
  • Deterministic tool-name assignment from a single naming source.
  • Internals: stdio transport now runs on kmet.libs.jsonrpc (child killed on
    close), JSON-RPC failures carry the request id in ex-data, and the stdio
    listener runs on concurrent/spawn.

Sessions and resume

  • Listings stream newest-first with per-file progress; filters and search
    apply while loading and the selection follows the chosen session by path.
  • Closing the selector or choosing a session stops an in-flight scan, and a
    superseded load's late result is dropped.
  • Loaded rows and the cursor survive empty partial snapshots, and toggling
    to an uncached scope no longer leaves the previous scope's rows on screen.

Terminal UI

  • The dock was rebuilt around an ordered panel stack with one leaving verb
    and a consistent close path for overlays.
  • Tool status lines are now opt-in (:status true) and ride a tail line that
    only changes its text color on settle, so a finished tool can no longer
    dirty scrollback. bash, run_code, and clojure_eval opt in.
  • The live terminal size is a reactive ref: the config screen reflows on
    resize and panel chrome follows theme switches.
  • Default theme palettes were aligned with pi's OKHSL palettes.
  • Component disposal fixes (transient Markdown/Image blocks, the autocomplete
    list, ExpandableText, chat-history placeholders and status lines) and a
    bounded kill ring.
  • Fixes: ordered-list source numbering in Markdown, wrapped table-cell
    borders, kitty image id reuse across reflows, and OSC 8 escape stripping in
    the plain-text helper.

Tools and the agent loop

  • script → run_code, with the model-facing text aligned to the DSH
    programmatic-tool-calling wording; full bash and code call lines render in
    the transcript.
  • Parallel tool calls settle as each one finishes; timed-out partials are
    kept and retry reasons reported; a cancel that lands before the active LLM
    call is installed is delivered; escape aborts only the compaction.
  • Process-tree kills are parents-first in the ps-walk fallback.

Models and providers

  • GPT-6 Sol and GPT-6 Luna added to Codex; Codex defaults to GPT-6.1 Sol with
    pi's none-reasoning set; GPT-5.6 Sol costs corrected; catalogs regenerated.
  • --generate-models now fetches provider and image model catalogs into
    ~/.kmet/agent/; image-catalog generation is bundled into generate-models.
  • GitHub Copilot sends its dynamic headers on every Copilot wire.
  • /share now handles a successfully authenticated share.

Extensions

  • Tool renderers can opt into the transcript tail status line with :status true; state-result-nodes and render-code-call are public renderer helpers.
  • Parallel batches: on-tool-call hooks run sequentially during preparation,
    while on-tool-result hooks run per tool and may overlap.
  • Print-mode extension contexts are wired to the running agent; :model-select
    records and resolved Model records are returned from contexts, and
    :scoped-models resolves to Model records.
  • The extension UI registry is cleared when a mode ends.
  • Dependencies: cljfmt 0.16.6; clojure.data.xml dropped from the shared set.

Clojure extension

  • New clojure_eval nREPL tool, with port-file discovery and common-port probing.
  • clojure_paren_repair is now strictly delimiter-only (no reformatting).
  • The shape validator accepts the full defn grammar, multi-line docstrings,
    and cross-type inserts.

Jolt and Windows

  • Jolt floor tracks the latest tagged release; the v0.8.15 java.time and
    file-URI fixes are adopted and their workarounds retired; /quit shuts the
    agent pool down so Jolt exits cleanly; pack-extension! runs on Jolt.
  • Windows/WSL: WSL bash alias detection for -s stdin, taskkill process-tree
    kill, POSIX chmod guards, and normalized test paths.

Developer workflow and docs

  • Duration and deadline measurement is unified on a monotonic clock, with a
    guard test pinning the rule.
  • Attribution enforcement (commit-msg hook and CI) blocks AI attribution in
    commits and PR text.
  • Changed-file tasks: lint dependency closure closed and ignored directories
    never walked; a SOCKS-proxy test race fixed.
  • Docs: pi built-in tools reference added, Jolt/Windows ticket tracking
    updated, and scripts/ documented in the project layout.

v0.1.0

Choose a tag to compare

@markokocic markokocic released this 27 Sep 20:37

First release