The compacted event handler injected a system-tagged reminder into the
live query after SDK auto-compaction, which caused the agent to send
an unintended message. Reverts the four changes from #2327:
- Remove `compacted` variant from ProviderEvent union
- Restore `result` yield for compact_boundary in ClaudeProvider
- Remove compacted event handler and getAllDestinations import in poll-loop
- Remove compaction integration tests and CompactingProvider helper
Closes#2325 differently — the reminder approach is not viable.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The container opens inbound.db read-only, so it can't ALTER TABLE.
If the host hasn't run migrateMessagesInTable yet (e.g., container
rebuilt before host restart), the on_wake column won't exist and
the query crashes, causing a restart loop.
Detect the column via PRAGMA table_info and conditionally include
the filter clause.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sweep of outbound strings, doc URLs, comments, and clone instructions
that were missed in the original org rename. One both-match case in
setup/lib/channels-remote.sh (URL detection) accepts either name so
existing forks with a `qwibitai` remote continue to resolve cleanly;
everywhere else is a straight rename.
Historical mentions left intact:
- CHANGELOG.md (v2.0.0 entry, frozen history)
- .claude/skills/add-gmail-tool/SKILL.md (pre-v2 qwibitai skill — historical)
- repo-tokens/badge.svg (auto-regenerated by update-tokens.yml)
Addresses review feedback on this branch:
- Fix TS2352 build error in dispatch.ts: `getSession()` returns `Session`,
which has no index signature, so `(s as Record<string, unknown>)` is rejected
by tsc. `Session.agent_group_id` exists — read it directly.
- Fix a regression introduced by dropping the `groupField in data` guard:
the post-handler scope check now runs for *every* command under a whitelisted
resource, including custom ops, which return ad-hoc shapes. `ncl groups config
get` (access:open, reachable by a group-scoped agent) returns a config object
with no `id` field → `data['id'] !== ctx.agentGroupId` → `forbidden`, even on
the agent's own config. Fix: tag the auto-generated list/get handlers with
`generic: 'list' | 'get'` on `CommandDef` (set in `registerResource`) and run
the post-handler check only when `cmd.generic` is set. Generic handlers return
raw DB rows that carry `scopeField`; custom ops are already pinned to the
caller's group by the pre-handler `--id` auto-fill or the approval gate.
Fail-closed-when-`scopeField`-missing is preserved (now scoped to generic
list/get).
- Tests: `dispatch.test.ts` mocks `getResource` (the real resources aren't
registered in this unit), tags the two post-handler test commands as `generic`,
and adds coverage for: custom op returning a non-row object not being rejected;
`sessions-get` pre-handler returning "session not found" for foreign and
non-existent UUIDs (no existence oracle) and allowing the caller's own session;
generic list/get failing closed when a resource declares no `scopeField`.
Full suite: 323 passing.
- Remove FORK.md from the PR diff — it's the fork's personal README, carried in
because the branch was cut from the fork's `main` rather than upstream.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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>