12 patch versions ahead. The 2.1.120 binary baseline introduced a
number of plugin and skill behaviors that have since landed in the
public Claude Code docs: ${CLAUDE_EFFORT} substitution, settled
`arguments` field in skill frontmatter, plugin `channels` field.
No breaking changes for nanoclaw's runtime contract. Verified by
running container/skills/{agent-browser,vercel-cli,slack-formatting}
under the bumped image; all three load and execute as expected.
SDK at ^0.2.116 (caret) remains compatible with claude-code 2.1.128.
Bumping CLAUDE_CODE_VERSION invalidates the pnpm install layer in
container/Dockerfile and triggers a full rebuild of the agent image.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Allow individual agent groups to opt into different models or effort levels
without changing host-wide defaults. Useful when one group is high-stakes
(opus, high effort) but most are routine (sonnet/haiku, low effort).
container.json gains two optional fields:
- model: alias ("sonnet" | "opus" | "haiku") or full model ID
- effort: "low" | "medium" | "high" | "xhigh" | "max"
Both omitted = SDK default (current behavior). The host plumbs them as
NANOCLAW_MODEL / NANOCLAW_EFFORT env vars at container spawn time; the
agent-runner reads them in providers/index.ts and threads through to the
provider via ProviderOptions. The Claude provider passes them straight to
sdkQuery options.
`effort` is currently typed as `any` because the @anthropic-ai/claude-
agent-sdk type doesn't surface it yet — passing it through still works at
runtime via the SDK's loose option handling. Drop the cast once the SDK
adds an `effort` field to its options type.
Explain that --message sets an on-wake instruction so the fresh
container can continue after restart (verify tools, notify user).
Without it, the container only comes back on the next user message.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
One-liner in cli.instructions.md pointing to `ncl groups config help`.
Each config operation's description now says whether restart or rebuild
is needed — agent discovers it via progressive disclosure.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Capture staged file list before prettier runs, then re-add only
those files. Prevents pulling in unrelated unstaged changes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The hook ran format:fix but didn't re-stage the modified files, so
commits went through with unformatted code and CI caught the diff.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Group-scoped agents could previously:
- See all agent groups via `groups list` (generic list skips --id filter)
- Look up any session by UUID via `sessions get`
- Request cli_scope change to global via config update approval
Fixed by:
- Post-handler filtering: list results filtered, get results verified
against caller's agent_group_id
- Pre-handler --id check scoped to resources where id IS the group ID
(groups, destinations) so session UUIDs aren't falsely rejected
- cli_scope/cli-scope args blocked outright for group-scoped agents,
before the approval gate
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When init-first-agent creates an agent group for an owner, set
cli_scope to 'global' so the owner's personal agent has full ncl
access. All other agent groups remain 'group'-scoped by default.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add cli_scope column to container_configs with three levels:
- disabled: agent never learns about ncl (instructions excluded from
CLAUDE.md) and host dispatch rejects any cli_request
- group (default): agent can only access groups, sessions, destinations,
and members resources, scoped to its own agent group with auto-filled
--id/--agent_group_id/--group args. Help output reflects the scope.
- global: unrestricted access (current behavior)
Enforcement is host-side only — no image rebuild or env var needed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Decouple container restart from config updates — config CLI ops now only
write to the DB; restart is a separate `ncl groups restart` command with
--rebuild and --message flags. Add on_wake column to messages_in so wake
messages are only picked up by a fresh container's first poll, preventing
dying containers from stealing them during the SIGTERM grace window.
killContainer accepts an onExit callback for race-free respawn. Agent-
called restart auto-scopes to the calling session.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
config add/remove-package should only update the DB and restart.
Image rebuild is handled by the self-mod approval flow or manually.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Operation keys like 'config get' read naturally and crud.ts normalizes
spaces to dashes for the registry name.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
`ncl groups config get` now works alongside `ncl groups config-get`.
Parser joins all positionals with dashes; dispatcher falls back by
trimming the last segment as a target ID (`ncl groups get abc123`).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The 5-minute timeout in buildAgentGroupImage was tight for first-time
apt + pnpm global installs on slow networks (the exact scenario
install_packages triggers, since the image hasn't pre-installed the
requested packages). Hit ETIMEDOUT on a real install with apt + npm
packages.
900_000ms gives realistic headroom without masking genuinely hung builds.
Source of truth for container runtime config moves from
groups/<folder>/container.json to a new container_configs table.
The file becomes a materialized view written at spawn time.
- New container_configs table with scalar columns (provider, model,
effort, image_tag, assistant_name, max_messages_per_prompt) and
JSON columns (mcp_servers, packages_apt, packages_npm, skills,
additional_mounts)
- Startup backfill seeds DB from existing container.json files
- materializeContainerJson() replaces readContainerConfig + ensureRuntimeFields
- Self-mod handlers (install_packages, add_mcp_server) write to DB
- Provider cascade simplified: session -> container_configs -> 'claude'
- ncl groups config-{get,update,add-mcp-server,remove-mcp-server,
add-package,remove-package} custom operations
- restartAgentGroupContainers() helper for config change propagation
- Container side unchanged (still reads /workspace/agent/container.json)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- genericList now accepts column filters (--flag value) and LIMIT (default 200)
- Remove early inDb.close() in container pollResponse to avoid double-close
- Document filtering and --limit in cli.instructions.md
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>