ncl is the admin CLI for a running NanoClaw host. It sends one request frame over a Unix socket at data/ncl.sock and prints the response — every command reads or mutates the host’s central database live, no restart needed. The socket is chmod 0600, so only the user that started the host can connect.
Don’t confuse it with the CLI channel, which is a chat adapter for talking to an agent from the terminal — ncl is for operating the host itself.
This page is the working tour. The ncl CLI reference has every operation, flag, and enum for all eleven resources.
Invoking ncl
Setup symlinks bin/ncl into ~/.local/bin, so after install you can run ncl from anywhere. From the project root, pnpm ncl works too:
ncl groups list
pnpm ncl groups list # equivalent, from the checkout
The general shape is:
ncl <resource> <verb> [target] [--key value ...] [--json]
Positional words join into the command name. A trailing positional becomes the target ID only if the ID contains no dashes — the dispatcher trims a single dash-segment, so ncl groups get abc123 works, but a real NanoClaw ID (a UUID, four hyphens) does not resolve. In practice, always pass --id <uuid>. Flags map to columns; hyphens and underscores are interchangeable (--agent-group-id = --agent_group_id). Run ncl help to list every resource, and ncl <resource> help for its verbs, columns, and enums.
Output and errors
By default ncl prints a human format: a small aligned table for list results, pretty-printed JSON for single objects, and error (<code>): <message> on failure. Pass --json to get the raw response frame instead — use that for scripting. Exit codes: 0 success, 1 command error, 2 transport error.
If the host isn’t running, ncl can’t reach the socket and tells you so:
ncl: cannot reach NanoClaw host (connect ENOENT .../data/ncl.sock).
Is the host running? Start it with: pnpm run dev
Or, if installed as a service:
macOS: launchctl kickstart -k gui/$(id -u)/com.nanoclaw-v2-<slug>
Linux: systemctl --user restart nanoclaw-v2-<slug>
Agents can run ncl too
The same command surface is exposed to agents inside containers. What an agent may do is controlled per group by cli_scope in its container config:
disabled — all ncl commands are rejected.
group (default) — the agent only sees the groups, sessions, destinations, and members resources, pinned to its own group: IDs are auto-filled, rows from other groups are filtered out, and it cannot change its own cli_scope.
global — full access to every resource.
Regardless of scope, mutating verbs (create, update, delete, grant, restart, …) are approval-gated for agents: the agent gets approval-pending and an admin receives a card showing the exact command. From the host socket, the same verbs run immediately — the socket file permissions are the auth boundary. Change the scope with:
ncl groups config update --id <group-id> --cli-scope disabled
Working with resources
Representative commands per resource — ncl <resource> help shows the full set.
groups
Agent groups: the agent identities with their own folder, history, and container image. Beyond CRUD, groups carries the container-config and lifecycle verbs.
ncl groups create --name "Research" --folder research
ncl groups restart --id <group-id> --rebuild
restart kills and respawns the group’s containers (--rebuild rebuilds the image first — required after package changes; --message <text> leaves an on-wake instruction). delete cascades through sessions, wirings, roles, memberships, and destinations in one transaction.
Config subcommands edit the group’s container_configs row — changes apply on the next restart:
ncl groups config get --id <group-id>
ncl groups config update --id <group-id> --model claude-sonnet-4-5 --effort high
ncl groups config add-mcp-server --id <group-id> --name fetch --command npx --args '["mcp-fetch"]'
ncl groups config add-package --id <group-id> --apt ffmpeg
config update accepts --provider, --model, --effort, --image-tag, --assistant-name, --max-messages-per-prompt, and --cli-scope.
messaging-groups and wirings
A messaging group is one chat on one platform (unique channel_type + platform_id); a wiring connects it to an agent group and sets engagement rules. List commands accept column filters and --limit:
ncl messaging-groups list --channel_type telegram
ncl wirings create --messaging-group-id <mg-id> --agent-group-id <group-id> --engage-mode mention-sticky
ncl wirings update --id <wiring-id> --session-mode per-thread
Wiring columns: engage_mode (mention | mention-sticky | pattern), engage_pattern, sender_scope (all | known), ignored_message_policy (drop | accumulate), session_mode (shared | per-thread | agent-shared).
users, roles, and members
Users are per-channel identities (tg:6037840640, discord:1234...). Roles grant privilege (owner is always global; admin can be global or scoped to one group with --group). Members let unprivileged users talk to a group when its wiring has sender_scope known.
ncl users create --id tg:6037840640 --kind telegram --display-name "Ethan"
ncl roles grant --user tg:6037840640 --role admin --group <group-id>
ncl members add --user tg:6037840640 --group <group-id>
roles revoke and members remove take the same flags.
sessions
Read-only view of the runtime units — one row per (agent group, messaging group, thread) with its container status (running | stopped; idle is reserved and currently unused):
ncl sessions list --agent_group_id <group-id>
dropped-messages
Read-only log of messages the router dropped, aggregated per sender and chat with a reason (no_agent_wired, no_agent_engaged, unknown_sender_strict, unknown_sender_request_approval). Your first stop when a message got no reply:
ncl dropped-messages list
approvals
Read-only view of in-flight approval cards waiting for an admin response:
ncl approvals list --status pending
destinations and user-dms
Destinations are per-agent send ACLs — each row lets an agent address a channel or another agent by a local name. user-dms is the read-only DM-route cache the host uses to cold-DM users.
ncl destinations list --agent_group_id <group-id>
ncl destinations add --agent-group-id <group-id> --local-name ops-channel --target-type channel --target-id <mg-id>
ncl user-dms list
Last modified on June 10, 2026