Pulled from GitHub Releases

Changelog

Every release of netclaw-dev/netclaw. Pick a version from the sidebar — this page rebuilds whenever a new release is published.

v0.12.0

Netclaw 0.12.0

0.12.0 2026-04-13

Netclaw v0.12.0 — KV cache-friendly session routing, Slack PDF/document ingress, durable working context, structured compaction, and security hardening

Features

  • Added cache-stable message assembly with a volatile User-role tail — memory recall, current time, and working-context layers used to be injected as System messages immediately after the persisted prompt, which broke llama.cpp prompt-cache prefix matching on every turn. A new SessionMessageAssembler now partitions outgoing messages so cache-stable content (persisted prompt, static dynamic context, conversation history) comes first and volatile content is consolidated into a single User-role tail. Combined with session-sticky routing (#610), multi-turn conversations reuse the KV cache across turns. (#618)

  • Added session-sticky LLM routing via X-Session-Id header — self-hosted inference servers behind a load balancer no longer defeat KV cache reuse across turns. A DelegatingHandler promotes the ambient session ID to an X-Session-Id HTTP header, which the load balancer can hash on (e.g., Caddy lb_policy header X-Session-Id) to pin same-session requests to the same backend GPU. Works automatically for all providers; managed providers (Anthropic, OpenAI, OpenRouter) safely ignore the header. Sidecar calls (compaction, title generation, memory extraction) bypass the header so they don't compete with the main session's cache slot. (#610)

  • Added llama.cpp timings parsing for cache and performance metrics — the OpenAI-compatible provider now surfaces KV cache hit counts (cache_n), prompt processing time (prompt_ms), and predicted throughput (predicted_per_second) from llama.cpp responses. New fields (cachedInputTokens, promptMs, predictedPerSecond, ttftMs, totalMs) flow through UsageOutput, the SignalR wire DTO, and the chat -p --json CLI envelope. Graceful degradation: all fields stay null for providers that don't emit timings. (#615)

  • Added --resume and -p flags to netclaw chat for scripted multi-turn sessions — netclaw chat -p "prompt" replaces the old top-level netclaw -p form, and netclaw chat -p --resume <id> "prompt" creates-or-resumes a named session so multi-turn evals, KV cache benchmarking, and compaction regression tests can run against the same session across turns. netclaw chat -p --json emits structured JSON (sessionId, response, toolCalls, usage) for machine consumption. (#613)

  • Added audience-gated attachment ingress contract with Slack PDF support — PDFs, DOCX files, and other non-image attachments were silently dropped from Slack messages with no feedback to the user. This release introduces a cross-channel ChannelAttachmentPolicy on ToolAudienceProfile with AllowedCategories, MaxFileBytes (default 25 MiB), and MaxFilesPerMessage (default 10). Public audiences allow images only; Team audiences allow everything except unknown binaries. Slack now downloads and surfaces non-image attachments consistently, and the agent gets a dynamic system-prompt hint explaining what it received and whether the active model can view it. (#601)

  • Added durable WorkingContext grounding that survives compaction and restart — sessions now persist a WorkingContext field alongside conversation state, containing RecentFiles (bounded ring buffer of 10, updated automatically by file-taking tools), OpenGoals, and ProgressMarkers. Unlike observer-reconstructed context, WorkingContext survives compaction, actor recovery, and daemon restart without depending on the observer LLM. (#598)

  • Added structured compaction summary with monotonic boundary — session compaction now uses a 9-section structured template (adopted from Cline's LLM harness) with explicit anti-drift rules, truncate-only-at-user-message-boundaries enforcement (adopted from OpenCode), and self-session-id disambiguation so the observer can mark foreign session IDs from tool-call history. SessionState.CompactionBoundaryIndex provides monotonic metadata pointing at the most recent session-summary marker. Fixes a Slack failure where a session lost its own ID after a compaction following a turn investigating another session. (#597)

  • Containerized netclawd and moved the behavioral eval suite into ephemeral Docker — docker/Dockerfile produces a release-grade ubuntu:24.04 image pre-installed with git, jq, sqlite3, python3, gh, and the netclaw + netclawd binaries. The eval suite now runs against a fresh container per invocation, so evals no longer contaminate the operator's real ~/.netclaw state with seeded test docs and LLM-formed memories. The same image is the supported Docker-deployment artifact for self-hosted netclawd. (#603)

  • Added multi-turn conversation eval category and Personal posture for the eval container — new Category 8 exercises chat -p --resume across 2-5 turn scripted sessions and captures per-turn KV cache and timing metrics. Adds a "Multi-Turn Cache Evolution" report section showing cached vs uncached token trending per turn, plus fixes a latent eval container misconfiguration that was silently degrading shell-using cases to tool-call-marker-only checks. (#616)

Bug Fixes

  • Fixed control-plane writes bypassing approval policy — agents could silently edit ~/.netclaw/config/netclaw.json and other control-plane files, which could trigger daemon restart and drop the active session mid-turn. ToolPathPolicy is now split into three independent deny surfaces (write-deny, read-deny, shell-indicators), and a new FilePathApprovalMatcher supports argument-aware control-plane approvals with path-scoped patterns like file_write:control-plane:netclaw.json. Approval-mode precedence is now deterministic for path-aware calls, and approve-once retry uses the same filtered unapproved pattern set the user saw in the prompt. Shell resource deny coverage is extended to lifecycle files (netclaw.db, netclaw.pid, netclaw.lock, cache/restart-manifest.json). (#617)

  • Fixed Slack attachment contract parity and hardening — SlackThreadHistoryFetcher no longer hard-filters thread-history attachments to image/*, so historical PDFs, DOCX files, and other non-image attachments are now downloaded and scanned consistently with live ingress. SlackThreadBindingActor replaces raw ex.Message in all user-facing rejected paths with stable messages (exception detail stays in structured logs). EscapeQuoted now strips control characters so hostile filenames can no longer embed newlines in the [attachment] announcement line. (#607)

  • Fixed Claude Code marketplaces and ~/.claude/commands skill resolution — the claude-code source alias now resolves to ~/.claude/skills, ~/.claude/commands, and every installed marketplace under ~/.claude/plugins/marketplaces/*/skills/, so marketplace skills like dotnet-skills are discoverable and ~/.claude/commands support is restored. Frontmatterless flat .md files are accepted only for the Claude commands path, matching current Claude Code behavior; non-commands paths still require valid YAML frontmatter. (#599)

  • Fixed system skills feed serving a stale manifest to daemons — publish_skills.yml was running wrangler pages deploy without pinning a branch, so release-tag builds (which run in detached HEAD) shipped the new manifest to a head.netclaw-feeds.pages.dev preview alias instead of the production custom domain. feeds.netclaw.dev had been frozen on the 2026-03-20 manifest for two releases, causing 5 of 6 skills to 404 on every daemon sync. The deploy now pins --branch=dev and a post-deploy propagation check asserts the published updatedAt matches the freshly generated manifest. (#606)

Internal

  • Disabled the publish-docker job in the release pipeline — Docker image publishing to GHCR is gated off until the Docker release path is green-lit. publish-binaries and the Cloudflare Pages manifest job are unaffected, and validate_docker_image.yml (PR build, no push) is untouched. (#620)