Netclaw v0.24.0 — Beta release channel, streaming-native chat stack, rebuilt config TUI, Docker reliability, and the full 0.24.0 beta journey
Major Features
-
Opt-in beta release channel — Netclaw can now publish and install prereleases without touching a default install. A new
latestPrereleasepointer (newest of all releases) works alongsidelatest(newest stable);--channel beta/-Channel betaand the rolling:betaDocker tag resolve to it. Stable clients only ever readlatest. (#1314) -
Channel-aware, SemVer-correct update check — the binary update check honors
Daemon.UpdateChannel(stabledefault, orbeta) and compares versions by SemVer 2.0.0 precedence. Beta testers are notified of the next prerelease and automatically roll onto stable once it supersedes; stable users are never offered a prerelease. (#1315) -
Streaming-native chat-client stack with composable routing — the
IChatClientstack has been redesigned so the streaming-vs-non-streaming transport distinction no longer leaks into callers. Netclaw now issues only streaming requests across all 8 providers, eliminating the OpenAI Codex400 "Stream must be set to true"error and preventing reasoning content drops. Resilience and observability are compositional viaMicrosoft.Extensions.AI.ChatClientBuilder— each (provider, model) pipeline is assembled asLogging → Retry → VendorOptions → raw. ARoutingChatClientwalks ordered candidate lists for failover, andLoggingChatClientis now stateless with session-correlated log tags (SessionId). (#1313) -
Rebuilt config TUI and simplified init wizard — the configuration TUI has been rebuilt from scratch with a streamlined init wizard, canonical channel-ID resolution for all gateway integrations, scrollable list views, and native text selection via Termina. (#1368, #1359, #1363)
-
Background jobs as detached processes — background jobs now run as detached processes with live log streaming, no default kill timer, and automatic reaping on passivation. (#1405)
-
Shell streaming support —
shell_executeoutput now streams incrementally instead of waiting for full completion, fixing the hard 90s timeout for long-running commands. (#1360) -
Standardized channel infrastructure (SPEC-015) — generic
ChannelLifecycleActorandRemoteChatChannelBuilderreduce new channel implementations to ~80 LOC (down from 1,100+ duplicated LOC across Discord and Mattermost), while enforcing a standardized security pipeline and gateway lifecycle. (#1375) -
Bounded tool output with file spill — large tool outputs are now bounded and spilled to a file instead of flooding the session, keeping context lean while preserving the full output on disk. (#1305)
-
Loud tool-argument validation — eliminated silent discard/degradation of LLM tool arguments; invalid arguments are now surfaced explicitly instead of being silently dropped. (#1398)
-
Channel delivery descriptor registry — new registration-based system for channel delivery descriptors, improving extensibility of channel integrations. (#1326)
-
lookup_channel_destinationblank-query support — passingquery: nullor an empty string now returns all available destinations, enabling "Select Destination" TUI steps. (#1375)
Bug Fixes
-
Discord gateway no longer enters zombie state after failed auto-retry — fixed a critical reliability issue where the Discord gateway dropped every inbound message for 30+ minutes and would not recover without a daemon restart. (#1374)
-
Mattermost auto-retry recovery publishes
ConnectionRestored— the same gateway-lifecycle fix applied to the Mattermost actor. (#1375) -
Scheduler race in BackgroundJobManagerActor startup eliminated — fixed a race condition in the scheduler's startup reconciliation logic that could cause jobs to be missed or duplicated during daemon initialization. (#1417)
-
In-session reminder delivery now confirms successfully — fixed current-session reminders that were incorrectly reporting delivery failures. (#1387)
-
Reminder list includes disabled reminders — the reminder list endpoint now correctly returns disabled reminders alongside active ones. (#1386)
-
Shell approval no longer matches bare integers or version/value arguments — fixed false-positive pattern matches on numeric arguments and normalized version/value handling in approval verb chains. (#1331, #1388)
-
Bound per-turn empty/thinking-only response loops — prevents agents from getting stuck in infinite loops of empty or thinking-only responses. (#1358)
-
Sub-agent logs are now session-correlated — sub-agent log output is properly tagged with session context, making it easier to trace sub-agent activity. (#1428)
-
MCP fixes — permission render clipping resolved; OAuth discovery skipped when static Authorization header is configured. (#1424, #1357)
-
Bounded image egress with dynamic resizing and caching — SkiaSharp-backed
IImageNormalizerdownscales images to bounded dimensions (~1568px long-edge cap) and a base64 byte budget (~5MB) with two seams: normalize-at-ingestion for chat attachments and downscale-at-egress with content-hash cache forfile_readimages. Fails loud (drop-with-note, never raw passthrough), preventing OOM on large images. Configurable caps with schema sync. (#1345) -
Secret placeholder writeback prevented — file read/write tools no longer write back secret placeholders. (#1343)
-
Model manager manual entry state reset — fixed stale manual entry state during model selection. (#1344)
-
Provider modality probing fixed — Netclaw no longer persists guessed modalities; model-probe timeout and visibility issues resolved. (#1311)
-
OpenAI Codex calls no longer hang — non-streaming Codex calls are served via streaming under the hood. (#1289)
-
Zero context-window models ignored — models reporting zero context window are now ignored instead of breaking model selection. (#1285)
-
Init wizard readiness race fixed — init readiness is gated on a daemon restart generation and a re-resolved endpoint. (#1307)
-
Standardized self-animating spinner across probe surfaces — replaced five hand-rolled spinners with Termina's shared
SpinnerNode; fixes frozen and slow spinners. (#1312, #1327) -
TUI approval detail toggle remapped —
Ctrl+V→Ctrl+O, freeing upCtrl+Vfor its expected use. (#1362) -
DaemonApi threaded into init wizard's provider step — init wizard's provider step now properly uses the DaemonApi. (#1369)
-
Flaky actor-startup tests fixed — deterministic readiness barriers replace timing assumptions. (#1410, #1378)
-
Removed skills pruned from server feeds — deleted skills no longer appear in the server's skill feed. (#1408)
-
Approval patterns terminate at multi-line arguments — multi-line shell arguments are properly terminated with a summary in the display text. (#1407)
-
Install scripts persist
--channelpreference —Daemon.UpdateChannelis now written tonetclaw.jsonduring--channel betainstalls, so the daemon no longer silently defaults to stable. (#1377) -
Lighter daemon memory footprint —
netclawdnow uses Workstation GC. (#1295) -
Windows installer uses User-scope PATH —
netclawis found in new shells. (#1274) -
Corrected version split in Directory.Build.props — version parsing handles all version strings correctly. (#1339)
Docker Improvements
-
Self-dropping CLI launcher for root exec —
/usr/local/bin/netclawtransparently re-execs as thenetclawuser when invoked as root, sodocker exec/kubectl execworks withoutgosu/-u. (#1322) -
Non-root agent can install tools at runtime in Docker — user-writable, on-
PATHinstall locations shipped so runtime-installed tools resolve as bare commands. (#1321) -
Docker no longer crash-loops on read-only
/toolsmount — treats/toolsas best-effort. (#1321) -
Docker reaps orphaned subprocesses — uses
tinito reap zombies. (#1306) -
Docker owns the daemon lifecycle — fixes conflicting restart behavior. (#1282)
-
Docker bind-mount ownership repaired — mounted data is writable on startup. (#1281)
-
Docker root-drop log cleanup — removed noisy log output when running as root. (#1342)
Shell Reliability
-
Shell pipe reads bounded — bounded to
MaxOutputCharsbefore truncating, preventing runaway memory. (#1298) -
Shell verifies the working directory — confirms the working directory exists before launching, surfacing a clear error. (#1299)
Dependency Updates
- Anthropic 12.24.1 → 12.29.1 (#1352, #1412)
- Termina 0.10.2 → 0.12.1 (#1354, #1393)
- Discord.Net 3.19.1 → 3.20.1 (#1353)
- Aspire.Hosting.AppHost 13.4.2 → 13.4.4 (#1318, #1366, #1413)
- Aspire.Hosting.Testing 13.4.2 → 13.4.3 (#1366)
- ModelContextProtocol.Core & ModelContextProtocol.AspNetCore 1.4.0 (#1329, #1330)
- CommunityToolkit.Aspire.Hosting.Ollama 13.4.0 (#1320)
- Grpc.Tools 2.81.0 → 2.81.1 (#1269, #1400)
- Verify.XunitV3 31.19.0 → 31.19.1 (#1270, #1367)
- Microsoft.AspNetCore.DataProtection 10.0.8 → 10.0.9 (#1404)
- Google.Protobuf 3.35.0 → 3.35.1 (#1399)
- OpenTelemetry 1.15.3 → 1.16.0 (#1392)
- slopwatch.cmd 0.4.1 → 0.4.2 (#1421)
- Akka group 2 updates (#1411)
Documentation & Internal
- Documented beta/stable release process (#1323)
- Cited #648 at the chat-client routing seam (#1335)
- Archived completed OpenSpec changes (#1325, #1380, #1389)
- Added
.claude/worktreesto.gitignore(#1336)