neru-add-cli-command
Add a Neru CLI command or flag: cobra command in internal/cli, IPC handler in internal/app/ipcctrl, service/mode work behind it, man pages, and docs/reference/cli.md. Use when adding or changing user-
Files2
View on GitHubSKILL.md.agents/skills/neru-add-cli-command/SKILL.md
GitHubAdding a CLI command to Neru
Neru is a daemon plus a thin CLI. Almost every command serializes an IPC
request to the running daemon over its per-user Unix socket or Windows named
pipe. A new command therefore touches three layers plus docs.
Skipping the IPC layer and calling app code directly from internal/cli is
wrong even when it compiles.
The chain
- Cobra command in
internal/cli/<name>.go, registered in aninit()like its siblings. Mode-shaped commands (hints/grid/scroll variants) go throughBuildModeCommand(ModeConfig{...})incommand_builders.goinstead of hand-rolling cobra. Look athints.gofirst. Long help text follows the house style: prose, then flag explanations, then anExamples:block. - IPC transport is already generic (
internal/adapter/ipc), so you only add an action string. Keep the wire shape in one place and reuse existing request helpers ininternal/cli/cliutil. - IPC handler in
internal/app/ipcctrl. Handlers register intoController.Handlersvia the sub-controller for their family (lifecycle,modes,actions,info,overlay,scroll, …). Extend the matchingRegisterHandlers, and don't add a case to the controller. - The actual work lives in
internal/app/services/*or a mode, never in the handler. Handlers parse, delegate, and shape theipc.Response. - Man pages: regenerate with
just genman(backed by./cmd/genman). Cobra metadata is the source, so if the man page reads wrong, fix the command'sShort/Long, not the output. - Docs: update
docs/reference/cli.md. It is the single home for CLI reference facts. - IPC reference: a new IPC command gets a row in the Commands table of
docs/reference/ipc.md.internal/architecture/ipc_reference_test.gofails while the table and the commands the daemon answers differ. - Schemas: when a reply type changes, run
just genschema.internal/architecture/ipc_schema_test.gofails whileschemas/ipc.schema.jsonis out of date.
Mode flags are different
A flag on a mode command (hints --action left_click) is not registered by
hand. It is one entry in the descriptor table in internal/domain/modecmd,
carrying its own parse, its own render, and the modes that accept it. That
entry is what offers the flag on the command line, what the daemon and the
config validator read it with, and what writes its row in the reference.
After adding, removing or re-wording one, run just genflagref to rewrite the
generated region of docs/reference/cli.md. An architecture test
(internal/architecture/mode_flag_contract_test.go) fails while a descriptor
is unregistered or missing from that region, and while a mode command offers a
flag the table never declared.
Tests
- Command wiring and flag parsing: follow the table-driven patterns in
internal/cli/cli_test.go/*_internal_test.go. - Handler behavior:
internal/app/ipcctrl/*_test.gowith port mocks frominternal/ports/mocks. Assert the response shape and that the right service call happened, not internals. - Anything platform-gated must degrade with
derrors.CodeNotSupported, and a contract test pins that (rootAGENTS.md, "Hard rules").
Verify
just build
./bin/neru <command> --help # against a running daemon: ./bin/neru launch
just genman
Then the standard pre-commit gate from AGENTS.md.