Releases: nanocoai/nanoclaw
v2.1.17
Rollup release covering v2.1.1 through v2.1.17 — every package.json bump merged since the v2.1.0 tag.
Changes
- [BREAKING]
@onecli-sh/sdk0.5.0 → 2.2.1 — requires a OneCLI server with the/v1API. Older servers 404 every SDK call. The sanctioned gateway and CLI versions are now pinned inversions.json, and theoneclisetup step enforces them. The gateway is a separate component — updating NanoClaw does not upgrade it for you:/update-nanoclawupgrades the gateway when its pin moves, otherwise upgrade manually. See docs/onecli-upgrades.md. - New agent provider: Codex (OpenAI) — run
/add-codex. Full runtime viacodex app-server(planning, MCP tools, server-side history, resume). Trunk ships the seams and the skill; the payload installs from theprovidersbranch — via the skill, the setup picker, or--step provider-auth codex. Auth is vault-only; no credential ever enters a container. - Setup can now select, install, and authenticate a non-default agent provider. A provider registry feeds the setup picker, an installer pulls the provider's payload from its branch, a vault auth walkthrough runs (
--step provider-auth), and the picked provider is set on the first agent — a DB property — before its first spawn. Default Claude installs are unaffected: picking Claude changes nothing. - Provider choice is explicit per group — no install-wide default. Provider is a DB property set via
ncl groups config update --providerplus a restart; group creation is provider-agnostic. /migrate-memoryruns the cross-provider memory move; runtime never touches it. Each provider keeps its own memory store, so fresh groups on a surfaces-owning provider see no staleCLAUDE.*files left over from another provider's writes. See docs/provider-migration.md./update-nanoclawnow upgrades the OneCLI gateway when its pinned version moves. Pairs with the OneCLI SDK 2.2.1 BREAKING above: the gateway upgrade that used to require a manual step is folded into the standard/update-nanoclawflow when the pin inversions.jsonshifts. Hosts whose gateway pin hasn't moved are unaffected.- Budget/billing-exhausted turns now reach the user instead of being silently dropped. When a turn ends in a non-retryable provider error — for example an Anthropic
403 billing_error— with no<message>wrapping, the agent-runner now delivers the provider's notice to the originating channel and stops re-nudging the failing gateway.providers/claude.tssurfaces the SDK'sis_errorflag and the error subtype'serrors[]text;poll-loop.tsdelivers that text and skips the re-wrap retry. Fixes the case where a spend-limit notice produced silence plus a turn-after-turn retry loop. - Command-gate denials now reach the sender.
writeOutboundDirectwas opening the session's outbound DB through the readonly opener, so the INSERT it ran threwSQLITE_READONLYon every call — the router'sPermission deniedresponse never delivered and the throw aborted further routing for that inbound event. Switched to the read-write opener (openOutboundDbRw, DELETE journal, busy_timeout); the host-side write stays even-seq, the container stays odd-seq, no contention. - Slash commands now interrupt an in-flight turn. A runner-handled command (
/clear,/compact,/cost, …) arriving mid-turn aborts the active stream and runs immediately instead of waiting for the turn to finish. - Container boot failures now say why. A 10-line stderr tail is kept per spawn and surfaced at
warnlevel on a non-zero exit (code !== null && code !== 0). Previously, a container that died at boot — unknown provider, missing binary, bad config — logged only atdebug, which is below the default level, so the failure vanished into a silent crash loop. - Egress lockdown (opt-in). Containers can be pinned to an allowlisted egress set via
ncl groups config update --egress-lockdown; outbound network calls outside the allowlist fail closed. Off by default. See docs/egress-lockdown.md. - Channel instances as a first-class dimension. A single channel kind — WhatsApp, Slack, … — can now run multiple independent instances per install, each with its own credentials, Chat SDK state, and webhook routes. Existing single-instance installs are preserved; the dispatcher falls back to
channelTypewhen noinstanceis set. - Native uninstaller.
bash uninstall.shfrom a checkout, ornanoclaw.sh --uninstallfrom the installed launcher, removes the service, the data directory, and the host registration in one step — no more manuallaunchctl bootout/systemctl --user disable. Includes--dry-runand a confirmation prompt; OneCLI agent registration is cleaned up alongside. - Interactive setup handoffs auto-submit context as Claude's first prompt. Mid-flow
?escapes and on-failure handoffs used to drop their context into--append-system-promptwith no user message, leaving Claude at an empty REPL while the operator re-explained themselves. Context now goes in as the first user message; handoffs in a single setup run also share a session-id (--session-idon the first spawn,--resumeon the next), so the conversation thread survives across mid-flow escapes. - Raw-route webhook registry. Channels register raw HTTP routes through a registry instead of patching the host's route table directly, so a new channel can be added without touching core. The non-Chat-SDK webhook suite kept its own file path to make the diff reviewable.
- Delivery-action getter. Channels expose a typed
getDeliveryActionso the host can route a message to the right send / edit / react path without channel-side branching at the call site. Read side of the action registry; the write side stays in the channel adapters. - Approval-resolved callback registry. Channels can register a callback that fires when an approval resolves — approved or rejected — used for in-channel acknowledgment cards and audit-trail edits.
- Per-exchange archiving is provider-owned. The
onExchangeCompletehook fires per turn; the markdown writer ships with the provider that needs it (codex payload), and the runner stops archiving on a provider's behalf. Dormant for the default Claude provider. - [security] A2A symlink guard. Inbound A2A payload resolution now fails closed on any symlink escape from the per-group sandbox — the resolver rejects forwarded attachments that traverse out via a symlink.
- [security] Approval admin authorization tightened. Approval response endpoints now require admin status and check the approver's scope against the request's group before executing — no cross-scope approvals.
- [security]
create_agenthost-side authorization. Agent creation is now authorized on the host side as well as the API edge: for confined groups, host-side approval is required, so a compromised channel can't spawn agents it isn't entitled to. host-sweepnow respects a per-group wake grace so it doesn't tear down a container that just woke and still has a stale processing claim.- Global agent-container CLI installs are data-driven via
container/cli-tools.json— skills add a CLI by appending a{name, version}JSON entry instead of patching the Dockerfile.agent-browseris now pinned to 0.27.1 (whatlatestlast resolved to); the rest is byte-for-byte unchanged. - Four skills retired (broken on v2 architecture):
claw,x-integration,add-parallel,convert-to-apple-container. References cleaned up inREADME.md,docs/SPEC.md,CONTRIBUTING.md, andCLAUDE.md. - Skills install model documented; see docs/skills-as-branches.md.
- Twelve skills retrofitted to the current skill contract:
add-dashboard,add-atomic-chat-tool,add-deltachat,add-slack,add-ollama-tool,migrate-from-openclaw,channel-family,opencodeprovider,codexprovider,mcp,capability,use-native-credential-proxy. - Ollama docs guide added for making the Ollama prompt cache hit on the Claude-Code → Ollama path: a small proxy filters the per-request
cch=<hash>the Claude Agent SDK prepends; in a 31B-on-Apple-Silicon setup, follow-up replies went ~80 s → ~4 s. Numbers vary by model. See docs/ollama.md. chat-sdk-bridgerecords the acting user on resolved approval/question cards in shared channels — appends a— <userName>byline to the edited card so the audit trail of who clicked Approve or Reject survives the button removal.@anthropic-ai/claude-code2.1.170 and@anthropic-ai/claude-agent-sdk0.3.170.
New Contributors
First NanoClaw PRs from @omri-maya, @markbala, @amit-shafnir, and @assapin landed in this release — welcome all four:
- @omri-maya — #2713
- @markbala — #2710
- @amit-shafnir — #2719
- @assapin — #2759
Want to be in the next one? Anyone can open a PR — pick up a good first issue or propose your own change directly. Discord is there if you want a hand getting started.
Contributors
Thanks to everyone who landed work in this release:
v2.1.0
Rollup release covering v2.0.65 through v2.1.0 — every package.json bump merged since the v2.0.64 tag.
Changes
- [BREAKING] Startup now requires an upgrade marker. The host refuses to boot unless
data/upgrade-state.jsonrecords that this install reached the current version through a sanctioned path (/setup,/update-nanoclaw,/migrate-nanoclaw). After this update completes — and before restarting the service — stamp the marker by runningpnpm exec tsx scripts/upgrade-state.ts set. If the host has already tripped on restart with "update did not go through the supported path", that same command clears it. (The tripwire code actually shipped in v2.1.1; v2.1.0 is the meaningful release boundary because the version bump and the feature merge sequenced in that order — every install on v2.1.1 or higher carries the tripwire.) See docs/upgrade-recovery.md. /upload-traceships the session transcript to Hugging Face. A runner-handled slash command (admin-gated, like/clear) pushes the current session's Claude Code transcript to the user's own private{hf_user}/nanoclaw-tracesdataset, browsable in the HF Agent Trace Viewer. Auth runs through the OneCLI gateway: the HF token is injected byHTTPS_PROXYand never touches agent code; a missing or unassigned token returns a clear setup message pointing at the gateway URL.- New
/add-rtkskill. Installs rtk into agent containers via host binary mount + a Claude CodePreToolUsehook, routing dev-loop commands through an output-summarizing proxy that saves 60–90% of tokens on compile/test/lint turns. Off by default — the skill opts a group in. - New
whatsapp-formattingcontainer skill. Inlined into every group'sCLAUDE.mdon container spawn (viaclaude-md-compose.ts) so agents see WhatsApp's mention syntax —@<phone-digits>sourced fromcontent.sender, never display names — on every reply. Without this, agents defaulted to@<displayName>, which WhatsApp can't tag: the @ rendered as plain text with no notification. Mirrors the existingcontainer/skills/slack-formatting/layout; pairs with the channels-branch fix that wiresmentionsthrough to Baileys'contextInfo. ncl groups deletenow cascades cleanly. Sessions, destinations, members, wirings, scheduled tasks, and dropped messages tied to a deleted group are removed in the same transaction — no orphan rows, no follow-up sweep needed.- Long-lived hub sessions now rotate their transcript before resume. The Claude provider checks the on-disk
.jsonlbacking the stored continuation before each--resume; if it exceeds 12 MB or its first entry is older than 14 days, an archived markdown summary is written toconversations/and a fresh session starts. Caps are operator-overridable viaCLAUDE_TRANSCRIPT_ROTATE_BYTESandCLAUDE_TRANSCRIPT_ROTATE_AGE_DAYS; both honor a zero/negative value as "disabled". Fixes the symptom where a hub that was responsive for days goes silent on a heavy turn because the SDK reloads the full transcript on every resume and the first turn alone exceeds the host's 30-min idle ceiling. - Outbound
<messages>envelope dropped — fixes the N>1 pending-message retry loop. When 2+ pending messages were bundled into<messages>...</messages>, the Claude Agent SDK returned a synthetic stub (model="<synthetic>",content="No response requested.") instead of calling the real API. The poll loop never marked the inbound row complete, the container exited, host-sweep respawned it with the same batch, and the transcript ballooned untiltries=5→ failed. Single-message turns were unaffected because they skipped the wrapper. Each<message id=... from=...>block is already self-contained, so dropping the outer envelope lets N>1 turns work the same way N=1 always has. - Persistent
inbound.dbcorruption now exits the container so host-sweep can respawn with a fresh mount. On Docker Desktop macOS, the kernel page cache for the bind-mountedinbound.dbcan latch a torn snapshot mid-host-write (a known virtiofs / gRPC-FUSE coherency issue); every fresh handle in the same process then sees the same broken view and emitsdatabase disk image is malformedat the poll rate. Reopening the handle inside the container does not recover — only a fresh container mount does. After ~5s of consecutive corruption errors (CORRUPTION_STREAK_EXIT), the runner exits with code 75 and host-sweep respawns it. Transient single torn reads are still tolerated. - Bumped
@anthropic-ai/claude-codeto 2.1.154 and@anthropic-ai/claude-agent-sdkto 0.3.154. - WhatsApp QR rendering wrapped so the QR block stays intact when piped through line-wrapping terminals.
- OneCLI base URL moved from
app.toapi.to match the new gateway DNS. setup-registerscope tightened so it can't register a group outside the operator's scope.- Channel approval targets are now authorized against the approving admin's scope — no cross-group approvals via crafted payloads.
signal-cli0.13+ identity field accepted; earlier versions kept working./add-teamsCLI docs corrected — previous version referenced flags that had been renamed.- Photon integration URL corrected from
photon.imtophoton.codesto match the new authoritative domain. CLAUDE.local.mdwrites now go through the SDK'ssettingSourcesplumbing so they survive a session reset.
New Contributors
First NanoClaw PRs from @claudiopostinghel, @snymanpaul, @mmahmed, @kartast, and @jonnychesthair-crypto landed in this release — welcome all five:
- @claudiopostinghel — #2551
- @snymanpaul — #2584
- @mmahmed — #2592
- @kartast — #2597
- @jonnychesthair-crypto — #2598
Want to be in the next one? Anyone can open a PR — pick up a good first issue or propose your own change directly. Discord is there if you want a hand getting started.
Contributors
Thanks to everyone who landed work in this release:
- @IamAdamJowett — #2553, #2556, #2586, #2595, #2596
- @gavrielc — #2637, #2648, #2690, #2691
- @glifocat — #2526
- @claudiopostinghel — #2551
- @guyb1 — #2558
- @kky — #2563
- @Hinotoi-agent — #2566
- @ira-at-work — #2571
- @snymanpaul — #2584
- @mmahmed — #2592
- @kartast — #2597
- @jonnychesthair-crypto — #2598
Full Changelog: v2.0.64...v2.1.0
v2.0.64
Changes
ncl destinations addandremovethrough the approval flow now reach the receiver immediately. Approved destinations weren't being projected into the receiving agent's local session state, so a freshly-added destination silently failed atsend_messagewithunknown destination, and a removed destination stayed resolvable until the next container restart. Both now take effect the moment the approval executes. Direct (non-approval) calls were unaffected.
Contributors
Full Changelog: v2.0.63...v2.0.64
v2.0.63
First properly published release. Starting with v2.0.63, the goal is to publish a GitHub Release for every
package.jsonversion bump that lands onmain— releases are cut manually by a maintainer, so there can be lag. Until now only the bumps landed and tags were sporadic, which made it hard for packagers and users to pin to a known version. See RELEASING.md for the policy.
Rollup release covering v2.0.55 through v2.0.63 — everything merged since the v2.0.54 tag.
Changes
- [BREAKING] Service names are now per-install. On v2 installs the launchd label and systemd unit are slugged to your project root:
com.nanoclaw.<sha1(projectRoot)[:8]>andnanoclaw-<slug>.service. The oldcom.nanoclaw/nanoclaw.servicenames no longer match a real service — update any copy-pasted restart or status commands. Find your install's names withsource setup/lib/install-slug.sh && launchd_label(macOS) orsystemd_unit(Linux). Thencltransport-error help text and 26 skill files now use the canonical helper-driven pattern; seesetup/lib/install-slug.sh. - Compaction destination reminder placement fixed. The reminder injected after SDK auto-compaction now appears at the end of the compaction summary so it isn't stripped during truncation. Replaces the placement shipped in v2.0.54.
- Stronger message-wrapping enforcement. The poll loop nudges the agent when its output lacks
<message>wrapping, andCLAUDE.mdcore instructions now require wrapping even for single-destination agents. The welcome flow no longer double-greets. - OneCLI credentials after MCP install. MCP servers added through
add_mcp_servernow inherit OneCLI gateway routing — fixes the case where the agent kept asking for API keys after installing a new server. - CLI scope hardening.
scopeFieldnow fails closed when scope is missing, andsessions getis guarded against cross-group oracle access from group-scoped agents. - gmail/gcal skills aligned with v2.
/add-gmail-tooland/add-gcal-toolnow reflect the v2 container-config model — DB-backed mounts, no deadTOOL_ALLOWLISTedits, nocontainer.jsonwrites that get clobbered on next spawn. Manual sqlite3/JSON1 invocations corrected. - Repo-rename cleanup. Remaining
qwibitai/nanoclawreferences swept tonanocoai/nanoclawacross code and docs; CI workflow guards updated so they no longer no-op after the rename. - Slack scope checklist now includes
files:readandfiles:writefor skills that read or post attachments. - The internal-tag description in destination instructions no longer mentions scratchpads (which confused agents into routing them incorrectly).
- Container startup is now graceful when the
on_wakecolumn is missing on older sessions DBs.
New Contributors
First NanoClaw PRs from @dvirarad and @intentionaleva landed in this release — welcome both:
Want to be in the next one? Anyone can open a PR — pick up a good first issue or propose your own change directly. Discord is there if you want a hand getting started.
Contributors
Thanks to everyone who landed work in this release:
- @johnnyfish — #2384
- @glifocat — #2392, #2402, #2408, #2489, #2493
- @dvirarad — #2400
- @gavrielc — #2410, #2412, #2413, #2414
- @Koshkoshinsk — #2442, #2467, #2473
- @intentionaleva — #2460
Full Changelog: v2.0.54...v2.0.63