mirror of
https://github.com/qwibitai/nanoclaw.git
synced 2026-07-12 19:00:58 +08:00
docs(harness): capability doc ([BREAKING] anchor), CHANGELOG entries, db-central + CLAUDE.md rows
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,8 @@ All notable changes to NanoClaw will be documented in this file.
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
- [BREAKING] **Claude's experimental agent-teams feature is now OFF by default for every group.** NanoClaw's agent-to-agent system (`create_agent` + destinations) is the authoritative multi-agent path; harness teams multiplied separately-billed agent contexts invisibly and its `SendMessage` collided with `mcp__nanoclaw__send_message`. Per-group settings.json is now *reconciled* on every spawn from the new `container_configs.harness_capabilities` column (defaults live in `src/harness-capabilities.ts`) — the legacy always-on `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` key is removed at each group's next spawn. **Migration:** [docs/harness-capabilities.md](docs/harness-capabilities.md) — re-enable per group with `ncl groups config update --id <g> --harness-capabilities 'agent-teams=on'` + `ncl groups restart --id <g>`.
|
||||
- [BREAKING] **The harness `Workflow` tool is now OFF by default for every group.** It duplicates NanoClaw's orchestration model, can spawn dozens of agents outside NanoClaw's visibility, and was the single largest per-turn schema (~26KB/turn including its agent-types catalog, measured on claude-code 2.1.197). Disabled via the reconciled `disableWorkflows` settings key plus a runner disallow backstop; `DesignSync` (desktop-only, 9.3KB/turn) joins the fixed disallow list with no toggle. **Migration:** [docs/harness-capabilities.md](docs/harness-capabilities.md) — re-enable per group with `ncl groups config update --id <g> --harness-capabilities 'workflow=on'` + `ncl groups restart --id <g>`.
|
||||
- **Claude tool allowlist reconciled with the pinned CLI, plus a tool-surface drift guard.** `TOOL_ALLOWLIST` in the agent runner named five tools that don't exist on claude-code 2.1.197 (`Task` — renamed `Agent` upstream — plus `TodoWrite`, `TeamCreate`, `TeamDelete`, `ToolSearch`); the phantom entries are removed and the comment corrected: `allowedTools` is a permission auto-approve list, **not an availability filter** — paired wire captures show no allowlist effect on the offered tool surface, and `bypassPermissions` moots its permission role. (The surface itself shows run-to-run variance in conditional tools on this CLI pin, so neither `allowedTools` nor `disallowedTools` alone should be relied on to shape what the model sees — the runner's PreToolUse hook is the deterministic block.) No wire-visible behavior change. A new wire-captured fixture (`container/agent-runner/src/providers/sdk-tools-baseline.json`) and `claude.tools.test.ts` now fail on any future claude-code CLI **or SDK** pin bump until the fixture is regenerated with `dump-sdk-tools.ts` and the lists re-verified.
|
||||
- [BREAKING] **`whatsapp-formatting` and `slack-formatting` container skills moved from trunk to the `channels` branch.** They now install with their channel — `/add-whatsapp` / `/add-slack` and the setup installers copy them in — so installs without those channels stop carrying channel-specific formatting instructions in every agent's context. **Migration — only if this install has the channel wired** (check `src/channels/whatsapp.ts` / `src/channels/slack.ts`): updating removes both skills from the working tree — WhatsApp agents lose the formatting fragment from their composed CLAUDE.md on next spawn, Slack agents lose the mrkdwn skill from `~/.claude/skills`. Re-run the matching skill, `/add-whatsapp` or `/add-slack` (idempotent), to restore. Installs without the channel need nothing — do NOT run the add-skill just in case; it installs the full channel adapter.
|
||||
- **Pre-task script failures back their series off instead of spinning.** A `--script` that errors lands the occurrence as a failed run (`script-skip:error` ack → `failed` status); recurrence reads the series' trailing failed streak and re-arms at `max(cron next, now + 2·2^(n−1) min, cap 60)`; after 8 consecutive failures the series is auto-paused with a host-written note in its run log (`ncl tasks resume` revives it). A deliberate `wakeAgent:false` gate is a normal run and never backs off. Also fixed: an explicitly-addressed `<message to>` in a task fire's final text now delivers as a deliberate send (previously suppressed as a turn-reply echo → zero delivery when the agent skipped the MCP tool); identical echoes of an MCP send are dropped in the runner, where the duplication originates.
|
||||
|
||||
@@ -73,6 +73,7 @@ For ad-hoc queries from skills or scripts, use the in-tree wrapper rather than t
|
||||
| `src/modules/permissions/user-dm.ts` | Cold-DM resolution + `user_dms` cache |
|
||||
| `src/group-init.ts` | Per-agent-group filesystem scaffold (CLAUDE.md, skills) — agent-runner source is a shared read-only mount, not copied per group |
|
||||
| `src/db/container-configs.ts` | CRUD for `container_configs` table (per-group container runtime config) |
|
||||
| `src/harness-capabilities.ts` | Harness-capability registry — `agent-teams`/`workflow` toggles (both default off), resolved into `container.json`; settings reconciler lives in `group-init.ts`. See [docs/harness-capabilities.md](docs/harness-capabilities.md) |
|
||||
| `src/backfill-container-configs.ts` | Migrates legacy `container.json` files into the DB on startup |
|
||||
| `src/container-restart.ts` | Kill + on-wake respawn for agent group containers |
|
||||
| `src/db/` | DB layer — agent_groups, messaging_groups, sessions, container_configs, user_roles, user_dms, pending_*, migrations |
|
||||
@@ -141,7 +142,7 @@ Per-agent-group container runtime config (provider, model, packages, MCP servers
|
||||
| Value | Behavior |
|
||||
|-------|----------|
|
||||
| `disabled` | Agent never learns about ncl (instructions excluded from CLAUDE.md). Host dispatch rejects any `cli_request`. |
|
||||
| `group` (default) | Agent can access `groups`, `sessions`, `destinations`, `members`, `tasks` only, scoped to its own agent group. `--id` and group args are auto-filled. Cross-group access rejected. `cli_scope` changes blocked. |
|
||||
| `group` (default) | Agent can access `groups`, `sessions`, `destinations`, `members`, `tasks` only, scoped to its own agent group. `--id` and group args are auto-filled. Cross-group access rejected. `cli_scope` and `harness_capabilities` changes blocked. |
|
||||
| `global` | Unrestricted. Set automatically for owner agent groups via `init-first-agent`. |
|
||||
|
||||
Key files: `src/db/container-configs.ts`, `src/container-config.ts`, `src/cli/dispatch.ts` (scope enforcement), `src/claude-md-compose.ts` (instructions exclusion).
|
||||
|
||||
@@ -320,12 +320,14 @@ CREATE TABLE container_configs (
|
||||
packages_npm TEXT NOT NULL DEFAULT '[]',
|
||||
additional_mounts TEXT NOT NULL DEFAULT '[]',
|
||||
cli_scope TEXT NOT NULL DEFAULT 'group', -- disabled | group | global
|
||||
harness_capabilities TEXT NOT NULL DEFAULT '{}', -- sparse overrides: {"agent-teams"|"workflow": "on"|"off"}
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
```
|
||||
|
||||
- **Readers:** `src/container-config.ts`, `src/container-runner.ts`, `src/cli/dispatch.ts` (scope enforcement), `src/claude-md-compose.ts`
|
||||
- **Writers:** `src/db/container-configs.ts`, `src/modules/self-mod/apply.ts`, `src/backfill-container-configs.ts`
|
||||
- `harness_capabilities` stores per-group overrides only; code defaults + resolution live in `src/harness-capabilities.ts` (see [harness-capabilities.md](harness-capabilities.md))
|
||||
|
||||
### 1.16 `pending_sender_approvals`
|
||||
|
||||
@@ -425,6 +427,7 @@ Several early migrations were later renamed/retired and replaced by "module" fil
|
||||
| 16 | `messaging-group-instance` | `016-messaging-group-instance.ts` | `messaging_groups` gets an `instance` column (adapter-instance dimension); table recreate (`disableForeignKeys: true`) backfills `instance = channel_type` on every existing row and relaxes the `UNIQUE` to `(channel_type, platform_id, instance)` |
|
||||
| 17 | `agent-message-policies` | `017-agent-message-policies.ts` | `agent_message_policies` (see §1.18) |
|
||||
| 18 | `approvals-approver-user-id` | `018-approvals-approver-user-id.ts` | `pending_approvals.approver_user_id` — names a single required approver for a2a message-gate policies |
|
||||
| 19 | `harness-capabilities` | `019-harness-capabilities.ts` | `ALTER TABLE container_configs ADD COLUMN harness_capabilities` — per-group harness toggles (see [harness-capabilities.md](harness-capabilities.md)) |
|
||||
|
||||
Numbers 5 and 6 are intentionally absent — migrations were renumbered during early development.
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# Harness capabilities
|
||||
|
||||
NanoClaw disables harness-native features that overlap its own systems, and exposes a small per-group toggle surface for the ones where both states are meaningful. Policy (keys, defaults, resolution) lives host-side in [`src/harness-capabilities.ts`](../src/harness-capabilities.ts); per-group overrides live in the `harness_capabilities` column of `container_configs`; mechanisms live in the agent runner and the settings reconciler ([`src/group-init.ts`](../src/group-init.ts)).
|
||||
|
||||
## Capability table
|
||||
|
||||
| Capability | Key | Default | Mechanism |
|
||||
|---|---|---|---|
|
||||
| Agent teams (experimental multi-agent coordination inside one session) | `agent-teams` | **off** | Settings reconciler adds/removes `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS` in the group's `settings.json` on every spawn. On the pinned CLI, settings env strictly beats SDK options env, so the settings file is the only working switch. |
|
||||
| Workflow tool (in-session multi-agent orchestration scripts) | `workflow` | **off** | Reconciler sets `disableWorkflows: true` (removes the tool and its agent-types catalog — ~26KB/turn); the runner also adds `Workflow` to `disallowedTools` + PreToolUse hook as a backstop. |
|
||||
| Cron/scheduling (`CronCreate/CronDelete/CronList`, `ScheduleWakeup`) | — | fixed off | `disallowedTools` + hook. NanoClaw's `schedule_task` MCP suite is the authoritative scheduler. |
|
||||
| `AskUserQuestion` | — | fixed off | `disallowedTools` (returns a placeholder headless; `ask_user_question` is the real mechanism). |
|
||||
| Plan/worktree modes | — | fixed off | `disallowedTools` (broken headless). |
|
||||
| `DesignSync` | — | fixed off | `disallowedTools` (desktop design-tool integration; nothing to sync with in a container; ~9.3KB/turn schema). |
|
||||
| Task list (`TaskCreate/…`), subagents (`Agent`), web (`WebSearch/WebFetch`) | — | fixed on | No NanoClaw overlap. Harness task lists are per-session scratch — not NanoClaw scheduled tasks. |
|
||||
|
||||
Toggling:
|
||||
|
||||
```bash
|
||||
ncl groups config get --id <group-id> # shows raw overrides + resolved view
|
||||
ncl groups config update --id <group-id> --harness-capabilities 'agent-teams=on'
|
||||
ncl groups config update --id <group-id> --harness-capabilities 'workflow=on,agent-teams=default'
|
||||
ncl groups restart --id <group-id> # apply
|
||||
```
|
||||
|
||||
`default` clears the per-group override (it is never stored). Changes from inside a container are rejected — like `cli_scope`, this is operator-only.
|
||||
|
||||
## [BREAKING] Agent teams default off
|
||||
|
||||
- **Detect**: after updating, agents in a group that used Claude's experimental agent-teams feature lose team coordination (the expanded `Agent`/`SendMessage`/`TaskCreate`/`TaskList` schemas revert to baseline) at the group's next container spawn. `ncl groups config get` shows `agent-teams: off (default)`; the group's `.claude-shared/settings.json` no longer contains `CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS`.
|
||||
- **Why**: it overlaps NanoClaw's agent-to-agent system (`create_agent` + destinations routing), is experimental upstream, multiplies separately-billed agent contexts invisibly to NanoClaw ops, and its `SendMessage` invites confusion with `mcp__nanoclaw__send_message`.
|
||||
- **Fix**: `ncl groups config update --id <g> --harness-capabilities 'agent-teams=on'` then `ncl groups restart --id <g>`.
|
||||
- **Verify**: `ncl groups config get --id <g>` shows `agent-teams: on (override)`; the settings.json env key is back after the next spawn.
|
||||
- **Rollback**: the fix line above IS the rollback — per group, no code changes.
|
||||
|
||||
## [BREAKING] Workflow tool default off
|
||||
|
||||
- **Detect**: agents no longer have the `Workflow` tool; request payloads shrink ~26KB/turn. `ncl groups config get` shows `workflow: off (default)`.
|
||||
- **Why**: it is redundant with NanoClaw's orchestration model (sessions + a2a, host stays in control), can spawn dozens of agents invisible to NanoClaw ops, and is the single largest tool schema on every turn (21.3KB measured on CLI 2.1.197).
|
||||
- **Fix**: `ncl groups config update --id <g> --harness-capabilities 'workflow=on'` then `ncl groups restart --id <g>`.
|
||||
- **Verify / Rollback**: as above, with `workflow`.
|
||||
|
||||
## Notes for forks
|
||||
|
||||
- If your fork patched `SDK_DISALLOWED_TOOLS` in `container/agent-runner/src/providers/claude.ts`: the fixed list still lives there, but per-group state now composes through `buildDisallowedTools()` — re-apply your patch to the fixed list, or express it as capability keys if it fits.
|
||||
- The measured numbers above are for `@anthropic-ai/claude-code` 2.1.197 / SDK 0.3.197. When bumping the pin, `claude.tools.test.ts` fails until you regenerate the tool-surface fixture: run [`dump-sdk-tools.ts`](../container/agent-runner/src/providers/dump-sdk-tools.ts) inside the agent image (invocation in its header) and re-verify the allow/disallow lists against the new surface.
|
||||
Reference in New Issue
Block a user