Skip to content

Releases: nanocoai/nanoclaw

v2.1.17

17 Jun 14:51

Choose a tag to compare

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/sdk 0.5.0 → 2.2.1 — requires a OneCLI server with the /v1 API. Older servers 404 every SDK call. The sanctioned gateway and CLI versions are now pinned in versions.json, and the onecli setup step enforces them. The gateway is a separate component — updating NanoClaw does not upgrade it for you: /update-nanoclaw upgrades the gateway when its pin moves, otherwise upgrade manually. See docs/onecli-upgrades.md.
  • New agent provider: Codex (OpenAI) — run /add-codex. Full runtime via codex app-server (planning, MCP tools, server-side history, resume). Trunk ships the seams and the skill; the payload installs from the providers branch — 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 --provider plus a restart; group creation is provider-agnostic.
  • /migrate-memory runs 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 stale CLAUDE.* files left over from another provider's writes. See docs/provider-migration.md.
  • /update-nanoclaw now 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-nanoclaw flow when the pin in versions.json shifts. 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.ts surfaces the SDK's is_error flag and the error subtype's errors[] text; poll-loop.ts delivers 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. writeOutboundDirect was opening the session's outbound DB through the readonly opener, so the INSERT it ran threw SQLITE_READONLY on every call — the router's Permission denied response 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 warn level on a non-zero exit (code !== null && code !== 0). Previously, a container that died at boot — unknown provider, missing binary, bad config — logged only at debug, 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 channelType when no instance is set.
  • Native uninstaller. bash uninstall.sh from a checkout, or nanoclaw.sh --uninstall from the installed launcher, removes the service, the data directory, and the host registration in one step — no more manual launchctl bootout / systemctl --user disable. Includes --dry-run and 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-prompt with 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-id on the first spawn, --resume on 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 getDeliveryAction so 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 onExchangeComplete hook 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_agent host-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-sweep now 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-browser is now pinned to 0.27.1 (what latest last 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 in README.md, docs/SPEC.md, CONTRIBUTING.md, and CLAUDE.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, opencode provider, codex provider, 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-bridge records 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-code 2.1.170 and @anthropic-ai/claude-agent-sdk 0.3.170.

New Contributors

First NanoClaw PRs from @omri-maya, @markbala, @amit-shafnir, and @assapin landed in this release — welcome all four:

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:

Read more

v2.1.0

17 Jun 14:51

Choose a tag to compare

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.json records 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 running pnpm 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-trace ships 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-traces dataset, browsable in the HF Agent Trace Viewer. Auth runs through the OneCLI gateway: the HF token is injected by HTTPS_PROXY and never touches agent code; a missing or unassigned token returns a clear setup message pointing at the gateway URL.
  • New /add-rtk skill. Installs rtk into agent containers via host binary mount + a Claude Code PreToolUse hook, 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-formatting container skill. Inlined into every group's CLAUDE.md on container spawn (via claude-md-compose.ts) so agents see WhatsApp's mention syntax — @<phone-digits> sourced from content.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 existing container/skills/slack-formatting/ layout; pairs with the channels-branch fix that wires mentions through to Baileys' contextInfo.
  • ncl groups delete now 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 .jsonl backing 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 to conversations/ and a fresh session starts. Caps are operator-overridable via CLAUDE_TRANSCRIPT_ROTATE_BYTES and CLAUDE_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 until tries=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.db corruption now exits the container so host-sweep can respawn with a fresh mount. On Docker Desktop macOS, the kernel page cache for the bind-mounted inbound.db can 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 emits database disk image is malformed at 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-code to 2.1.154 and @anthropic-ai/claude-agent-sdk to 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. to api. to match the new gateway DNS.
  • setup-register scope 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-cli 0.13+ identity field accepted; earlier versions kept working.
  • /add-teams CLI docs corrected — previous version referenced flags that had been renamed.
  • Photon integration URL corrected from photon.im to photon.codes to match the new authoritative domain.
  • CLAUDE.local.md writes now go through the SDK's settingSources plumbing 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:

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:

Full Changelog: v2.0.64...v2.1.0

v2.0.64

18 May 18:01
0683c6e

Choose a tag to compare

Changes

  • ncl destinations add and remove through 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 at send_message with unknown 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

15 May 19:08
975a2f0

Choose a tag to compare

First properly published release. Starting with v2.0.63, the goal is to publish a GitHub Release for every package.json version bump that lands on main — 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]> and nanoclaw-<slug>.service. The old com.nanoclaw / nanoclaw.service names no longer match a real service — update any copy-pasted restart or status commands. Find your install's names with source setup/lib/install-slug.sh && launchd_label (macOS) or systemd_unit (Linux). The ncl transport-error help text and 26 skill files now use the canonical helper-driven pattern; see setup/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, and CLAUDE.md core 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_server now inherit OneCLI gateway routing — fixes the case where the agent kept asking for API keys after installing a new server.
  • CLI scope hardening. scopeField now fails closed when scope is missing, and sessions get is guarded against cross-group oracle access from group-scoped agents.
  • gmail/gcal skills aligned with v2. /add-gmail-tool and /add-gcal-tool now reflect the v2 container-config model — DB-backed mounts, no dead TOOL_ALLOWLIST edits, no container.json writes that get clobbered on next spawn. Manual sqlite3/JSON1 invocations corrected.
  • Repo-rename cleanup. Remaining qwibitai/nanoclaw references swept to nanocoai/nanoclaw across code and docs; CI workflow guards updated so they no longer no-op after the rename.
  • Slack scope checklist now includes files:read and files:write for 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_wake column 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:

Full Changelog: v2.0.54...v2.0.63