From 525e7c4c157f082599f2b53c29217bf4e2a21cfc Mon Sep 17 00:00:00 2001 From: Tim Beyer Date: Wed, 1 Apr 2026 11:34:12 +0200 Subject: [PATCH 1/4] chore: add task for CLI command skill and mount completions Co-Authored-By: Claude Opus 4.6 (1M context) --- .../2026-04-01_1133_cli-command-skill/TASK.md | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 tasks/2026-04-01_1133_cli-command-skill/TASK.md diff --git a/tasks/2026-04-01_1133_cli-command-skill/TASK.md b/tasks/2026-04-01_1133_cli-command-skill/TASK.md new file mode 100644 index 0000000..83629fa --- /dev/null +++ b/tasks/2026-04-01_1133_cli-command-skill/TASK.md @@ -0,0 +1,24 @@ +# CLI command skill + fix missing mount completions/README + +## Status: In Progress + +## Scope + +1. Create a skill that guides adding new CLI commands — ensures all touchpoints are updated +2. Move CLI command conventions from `docs/architecture.md` into the skill +3. Add `mount` to README commands table, shell completions, and completion tests + +## Context + +When the `clawctl mount` command was added, the README and shell completions were missed. There are 7 places that need updating when adding a CLI command, and no single reference that lists them all. A skill solves this by being loaded whenever someone is working on CLI commands. + +## Plan + +Create `.agents/skills/adding-cli-commands/` with a SKILL.md that contains the full checklist and conventions (instance resolution, positional args, subcommand groups). Move the CLI conventions section from `docs/architecture.md` into the skill's reference doc, and link back. Then fix the `mount` command gaps. + +## Steps + +- [ ] Create the skill with checklist and conventions +- [ ] Add `mount` to README commands table +- [ ] Add `mount` to bash/zsh completions and test +- [ ] Lint, format, test, commit From c58456d8f41f6103b2a3367d21db9c868235ba2a Mon Sep 17 00:00:00 2001 From: Tim Beyer Date: Wed, 1 Apr 2026 11:36:12 +0200 Subject: [PATCH 2/4] feat: add adding-cli-commands skill Checklist-driven skill ensuring all 7 touchpoints are updated when adding a CLI command. Moves CLI conventions from docs/architecture.md into the skill's reference doc. Co-Authored-By: Claude Opus 4.6 (1M context) --- .agents/skills/adding-cli-commands/SKILL.md | 56 ++++++++++++++++ .../references/cli-conventions.md | 65 +++++++++++++++++++ docs/architecture.md | 33 ++-------- 3 files changed, 125 insertions(+), 29 deletions(-) create mode 100644 .agents/skills/adding-cli-commands/SKILL.md create mode 100644 .agents/skills/adding-cli-commands/references/cli-conventions.md diff --git a/.agents/skills/adding-cli-commands/SKILL.md b/.agents/skills/adding-cli-commands/SKILL.md new file mode 100644 index 0000000..f6dc9f9 --- /dev/null +++ b/.agents/skills/adding-cli-commands/SKILL.md @@ -0,0 +1,56 @@ +--- +name: adding-cli-commands +description: "Add new CLI commands to clawctl. Use when creating a new command, subcommand group, or modifying the CLI surface. Ensures all touchpoints are updated: handler, exports, commander wiring, README, shell completions, and tests." +--- + +# Adding CLI Commands + +When adding a new command to clawctl, **7 places** need updating. +Missing any of them causes broken completions, missing docs, or test failures. + +## Checklist + +1. **Command handler** — `packages/cli/src/commands/.ts` + Create `export async function runCommandName(...)`. + For instance-targeting commands, use `requireInstance(opts)`. + +2. **Barrel export** — `packages/cli/src/commands/index.ts` + Add `export { runCommandName } from "./.js"` + +3. **Commander wiring** — `packages/cli/bin/cli.tsx` + Add `.command()` block with description, options, action handler. + Import the handler from the barrel export. + +4. **README** — `README.md` (commands table, around line 66) + Add a row with command syntax and description. + +5. **Bash completions** — `packages/templates/src/completions/bash.ts` + - Add to `local commands="..."` string (line 88) + - Add case in `case "$cmd" in` block with command-specific options + +6. **Zsh completions** — `packages/templates/src/completions/zsh.ts` + - Add to `commands=(...)` array (around line 70) + - Add case in `case ${words[1]} in` block with `_arguments` + +7. **Completion tests** — `packages/templates/src/completions/completions.test.ts` + Add to `ALL_COMMANDS` array (line 6) + +## Conventions + +See [references/cli-conventions.md](references/cli-conventions.md) for +instance resolution, positional argument rules, and subcommand patterns. + +## Subcommand groups + +Parent commands like `mount` and `daemon` need special handling: + +- **Commander**: Create parent with `.command("name")`, add `.action(() => cmd.help())` for bare invocation, nest children under it +- **Completions**: Add the parent to the top-level commands list. Add a case that completes subcommand names. Add nested cases for each subcommand's options. +- **README**: List each subcommand as its own row +- **Tests**: Add the parent command name to `ALL_COMMANDS` + +## Update check skip list + +If the command shouldn't trigger the auto-update check (infrastructure commands +like `update`, `daemon`, `completions`), add it to `SKIP_UPDATE_COMMANDS` in +`cli.tsx`. diff --git a/.agents/skills/adding-cli-commands/references/cli-conventions.md b/.agents/skills/adding-cli-commands/references/cli-conventions.md new file mode 100644 index 0000000..b02fb98 --- /dev/null +++ b/.agents/skills/adding-cli-commands/references/cli-conventions.md @@ -0,0 +1,65 @@ +# CLI Command Conventions + +## Instance resolution + +Every command that targets an instance uses `requireInstance(opts)` from +host-core. It resolves the instance in this order: + +1. Explicit `-i ` / `--instance ` flag +2. Local `.clawctl` context file (set by `clawctl use`) +3. Global context (`~/.config/clawctl/context.json`) +4. Error if none found + +## Positional `[name]` argument + +Commands that **only** target an instance (no other positional args) +offer `[name]` as a convenience positional: + +``` +clawctl status [name] # OK — no other positionals +clawctl start [name] # OK +clawctl mount list [name] # OK +``` + +Commands that have **other required positional arguments** must NOT use +`[name]` — Commander consumes the first positional as the optional name, +swallowing the real argument. Use `-i` or context resolution instead: + +``` +clawctl mount add # No [name] — would eat +clawctl mount remove # No [name] — would eat +``` + +## Subcommand groups + +Parent commands (`mount`, `daemon`, `completions`) use Commander's nested +command pattern: + +```typescript +const parentCmd = program + .command("parent") + .description("Description") + .action(() => { + parentCmd.help(); // Show help when called bare + }); + +parentCmd + .command("child") + .description("...") + .action(async () => { ... }); +``` + +For subcommands with required positional args, add `.showHelpAfterError(true)` +so missing arguments show usage instead of a cryptic error. + +## Naming conventions + +- Command handlers: `runCommandName` (e.g., `runMountList`, `runDaemonStart`) +- File names: kebab-case matching the command (e.g., `mount.ts`, `daemon.ts`) +- One file per command or command group + +## Error handling + +- Use `process.exit(1)` for user errors (not found, invalid args) +- Let exceptions propagate for unexpected errors +- `requireInstance()` handles its own error output and exits diff --git a/docs/architecture.md b/docs/architecture.md index 9794046..fb24029 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -241,35 +241,10 @@ The eventual goal is to keep Ink active during onboarding by embedding the subpr ## CLI Command Conventions -### Instance resolution - -Every command that targets an instance uses `requireInstance(opts)` from -host-core. It resolves the instance in this order: - -1. Explicit `-i ` / `--instance ` flag -2. Local `.clawctl` context file (set by `clawctl use`) -3. Global context (`~/.config/clawctl/context.json`) -4. Error if none found - -### Positional `[name]` argument - -Commands that **only** target an instance (no other positional args) -offer `[name]` as a convenience positional: - -``` -clawctl status [name] # OK — no other positionals -clawctl start [name] # OK -clawctl mount list [name] # OK -``` - -Commands that have **other required positional arguments** must NOT use -`[name]` — Commander consumes the first positional as the optional name, -swallowing the real argument. Use `-i` or context resolution instead: - -``` -clawctl mount add # No [name] — would eat -clawctl mount remove # No [name] — would eat -``` +See `.agents/skills/adding-cli-commands/` for the full checklist of +files to update when adding a command, and +`.agents/skills/adding-cli-commands/references/cli-conventions.md` for +instance resolution, positional argument rules, and subcommand patterns. ## Error Handling From 9f6bbfc3c4dbe936e2f37af709e8f9c2cb322f67 Mon Sep 17 00:00:00 2001 From: Tim Beyer Date: Wed, 1 Apr 2026 11:36:18 +0200 Subject: [PATCH 3/4] feat: add mount command to README and shell completions Add mount list/add/remove to the README commands table, bash and zsh completion scripts, and the completion test inventory. Co-Authored-By: Claude Opus 4.6 (1M context) --- README.md | 3 ++ packages/templates/src/completions/bash.ts | 31 +++++++++++++++- .../src/completions/completions.test.ts | 1 + packages/templates/src/completions/zsh.ts | 37 +++++++++++++++++++ 4 files changed, 71 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0de1ae5..821e2a1 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,9 @@ For automated setups, pass a JSON config file and skip the prompts — see [Head | `clawctl shell [name]` | Interactive shell into the VM | | `clawctl shell [name] -- ` | Run a command in the VM | | `clawctl openclaw ` | Run an `openclaw` command in the VM (alias: `oc`) | +| `clawctl mount list [name]` | List all mounts for an instance | +| `clawctl mount add ` | Add a host directory mount (`--writable` for rw) | +| `clawctl mount remove ` | Remove a user-added mount | | `clawctl use [name] [--global]` | Set or show the current instance context | | `clawctl register --project ` | Register an existing (pre-registry) instance | | `clawctl completions ` | Generate shell completion script (bash or zsh) | diff --git a/packages/templates/src/completions/bash.ts b/packages/templates/src/completions/bash.ts index 2278d1d..f94ee5a 100644 --- a/packages/templates/src/completions/bash.ts +++ b/packages/templates/src/completions/bash.ts @@ -85,7 +85,7 @@ export function generateBashCompletion(binName: string): string { fi done - local commands="create list status start stop restart delete shell register openclaw oc use" + local commands="create list status start stop restart delete shell register openclaw oc use mount" # Complete command name at position 1 if [[ \$COMP_CWORD -eq 1 ]]; then @@ -164,6 +164,35 @@ export function generateBashCompletion(binName: string): string { ;; esac ;; + mount) + if [[ \$COMP_CWORD -eq 2 ]]; then + COMPREPLY=( $(compgen -W "list add remove --help" -- "$cur") ) + else + local sub="\${COMP_WORDS[2]}" + case "$sub" in + list) + case "$prev" in + -i|--instance) + COMPREPLY=( $(compgen -W "$(_${fnName}_instances)" -- "$cur") ) + ;; + *) + if [[ "$cur" == -* ]]; then + COMPREPLY=( $(compgen -W "-i --instance --help" -- "$cur") ) + else + COMPREPLY=( $(compgen -W "$(_${fnName}_instances)" -- "$cur") ) + fi + ;; + esac + ;; + add) + COMPREPLY=( $(compgen -W "-i --instance --writable --no-restart --help" -- "$cur") ) + ;; + remove) + COMPREPLY=( $(compgen -W "-i --instance --no-restart --help" -- "$cur") ) + ;; + esac + fi + ;; completions) COMPREPLY=( $(compgen -W "bash zsh update-oc --help" -- "$cur") ) ;; diff --git a/packages/templates/src/completions/completions.test.ts b/packages/templates/src/completions/completions.test.ts index c5e28bc..e410426 100644 --- a/packages/templates/src/completions/completions.test.ts +++ b/packages/templates/src/completions/completions.test.ts @@ -16,6 +16,7 @@ const ALL_COMMANDS = [ "openclaw", "oc", "use", + "mount", ]; // -- Bash completion ---------------------------------------------------------- diff --git a/packages/templates/src/completions/zsh.ts b/packages/templates/src/completions/zsh.ts index 41a54e5..957a35f 100644 --- a/packages/templates/src/completions/zsh.ts +++ b/packages/templates/src/completions/zsh.ts @@ -80,6 +80,7 @@ export function generateZshCompletion(binName: string): string { 'openclaw:Run an openclaw command in the VM' 'oc:Run an openclaw command in the VM (alias)' 'use:Set or show the current instance context' + 'mount:Manage VM mount points' ) local state @@ -146,6 +147,42 @@ export function generateZshCompletion(binName: string): string { '--global[Set global context instead of local .clawctl file]' ${BS} '--help[Show help]' ;; + mount) + local -a mount_commands + mount_commands=( + 'list:List all mounts for an instance' + 'add:Add a host directory mount to the VM' + 'remove:Remove a mount from the VM' + ) + if (( CURRENT == 2 )); then + _describe 'mount command' mount_commands + else + case \${words[2]} in + list) + _arguments ${BS} + '1:instance name:_${fnName}_instances' ${BS} + '(-i --instance)'{-i,--instance}'[Instance to target]:instance name:_${fnName}_instances' ${BS} + '--help[Show help]' + ;; + add) + _arguments ${BS} + '1:host path:_directories' ${BS} + '2:guest path:' ${BS} + '(-i --instance)'{-i,--instance}'[Instance to target]:instance name:_${fnName}_instances' ${BS} + '--writable[Mount as read-write]' ${BS} + '--no-restart[Update config but do not restart the VM]' ${BS} + '--help[Show help]' + ;; + remove) + _arguments ${BS} + '1:guest path:' ${BS} + '(-i --instance)'{-i,--instance}'[Instance to target]:instance name:_${fnName}_instances' ${BS} + '--no-restart[Update config but do not restart the VM]' ${BS} + '--help[Show help]' + ;; + esac + fi + ;; completions) _arguments '1:shell:(bash zsh)' '--help[Show help]' ;; From ab0f1c074cb43b7cde4d2403ff47ab624d40cab7 Mon Sep 17 00:00:00 2001 From: Tim Beyer Date: Wed, 1 Apr 2026 11:36:36 +0200 Subject: [PATCH 4/4] chore: mark CLI command skill task as resolved Co-Authored-By: Claude Opus 4.6 (1M context) --- tasks/2026-04-01_1133_cli-command-skill/TASK.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tasks/2026-04-01_1133_cli-command-skill/TASK.md b/tasks/2026-04-01_1133_cli-command-skill/TASK.md index 83629fa..44a68ef 100644 --- a/tasks/2026-04-01_1133_cli-command-skill/TASK.md +++ b/tasks/2026-04-01_1133_cli-command-skill/TASK.md @@ -1,6 +1,6 @@ # CLI command skill + fix missing mount completions/README -## Status: In Progress +## Status: Resolved ## Scope @@ -18,7 +18,7 @@ Create `.agents/skills/adding-cli-commands/` with a SKILL.md that contains the f ## Steps -- [ ] Create the skill with checklist and conventions -- [ ] Add `mount` to README commands table -- [ ] Add `mount` to bash/zsh completions and test -- [ ] Lint, format, test, commit +- [x] Create the skill with checklist and conventions +- [x] Add `mount` to README commands table +- [x] Add `mount` to bash/zsh completions and test +- [x] Lint, format, test, commit