Skip to content

Move the Claude Code plugin here: /onctl:on routes Bash to a box - #1175

Merged
cdalar merged 1 commit into
mainfrom
feat/claude-plugin
Oct 5, 2026
Merged

cdalar merged 1 commit into
mainfrom
feat/claude-plugin

Conversation

@cdalar

@cdalar cdalar commented Oct 5, 2026

Copy link
Copy Markdown
Owner

Rollout step 4 of docs/plans/boxes-provider.md: boxctl's Claude Code plugin moves to claude-plugin/ as onctl.

/plugin marketplace add cdalar/onctl
/plugin install onctl@onctl
/onctl:on [--mode session|project|exec] [--workspace sync|copy|git|none] ...
/onctl:status   /onctl:off   /onctl:handoff [note]

What changed in the helper (bin/onctl-claude) — it now drives onctl instead of boxctl:

  • Finding and managing boxes: onctl ls -p boxes -o json (via jq, independent of table layout), onctl create / resume / destroy. The stored --size becomes onctl's --type.
  • Reaching a box: plain ssh with onctl ssh-proxy -p boxes as its ProxyCommand, replacing boxctl's background port-forward process and its pid/port files. A shared master connection still makes each sync a single round trip. Keepalives let a master from before a pause give way, and there's one retry when ssh itself (not the command) failed.
  • Commands: the 5-minute limit now runs on the box with timeout. Exit codes pass through, and ssh's own "mux_client" noise is filtered from the command's stderr.
  • Exec mode: creates and destroys a box per command itself, since onctl has no exec command.
  • No more leaked boxes: a session box whose workspace setup fails is now destroyed instead of left behind.
  • The ssh key is shared with onctl claude; boxctl's existing key is reused, so boxes either tool set up work with both.

Hooks, slash commands and the skill are renamed. Commands starting with onctl (or boxctl , or a # local line) stay local.

Tested live, against boxctl.io (every box destroyed afterwards):

  • Session mode with sync:
    • the hook rewrote a Bash call;
    • the command ran on the box and the file it wrote synced back;
    • the git-ignored node_modules stayed local and wasn't deleted;
    • the working directory carried over;
    • exit code 7 passed through;
    • a 3s timeout stopped sleep 10;
    • off destroyed the box.
  • Exec mode: a fresh box ran the command and was destroyed, in 4.9s, with exit code 3 passed through.
  • Project mode across a pause: the next command resumed the box and succeeded, after about 18s while the stale connection timed out.

Bugs found and fixed while testing:

  • the state directory wasn't created when reusing boxctl's key, so ssh's ControlPath failed;
  • exec mode's random name pipeline hit SIGPIPE under pipefail;
  • the session-box leak above.

bash -n and shellcheck are clean; the JSON files validate.

Not tested: the plugin loaded inside a real Claude Code session (the hooks were exercised directly), and /onctl:handoff, which calls onctl claude --handoff.

After this merges, step 5 retires boxctl, including its own copy of the plugin.

🤖 Generated with Claude Code

https://claude.ai/code/session_01U8g3mHkS6JmtYVYc4AjcV4

Rollout step 4 of docs/plans/boxes-provider.md. boxctl's plugin moves
into claude-plugin/ as 'onctl' (marketplace cdalar/onctl, /onctl:on,
/onctl:off, /onctl:status, /onctl:handoff, the onctl-remote-bash skill).

Its helper (bin/onctl-claude) now drives onctl:
- boxes are found with onctl ls -o json, created, resumed and destroyed
  with onctl;
- ssh reaches a box through onctl ssh-proxy as its ProxyCommand rather
  than a background port-forward, with keepalives so a master
  connection left from before a pause gives way, and one retry when ssh
  itself (not the command) failed;
- the per-command timeout runs on the box (timeout), exit codes pass
  through;
- exec mode creates and destroys a box per command itself.

A session box whose workspace setup fails is now destroyed instead of
left behind. The key is shared with onctl claude, boxctl's reused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U8g3mHkS6JmtYVYc4AjcV4
@cdalar
cdalar enabled auto-merge (squash) October 5, 2026 05:23
@cdalar
cdalar merged commit b72fddc into main Oct 5, 2026
12 checks passed
cdalar added a commit that referenced this pull request Oct 9, 2026
The plugin lives in cdalar/boxctl (/boxctl:on ...), where it drives the
boxctl CLI. The copy made here as 'onctl' (#1175) did the same job with
a second 500-line helper to keep in step, had no users, and since #1177
couldn't be installed from its marketplace at all: that pointed at a
plugin-stable branch only a release creates, and none has been cut.

Removes claude-plugin/, .claude-plugin/marketplace.json, the
plugin-release workflow, the plugin hint in onctl login (with its test)
and the paragraph in onctl claude --help, and the README line. login.go
and claude.go are back to what they were before #1176.

The boxes provider, ssh-proxy, port-forward, sizes and onctl claude are
unaffected; none of them used the plugin. The plan doc now says steps 4
(the plugin) and 5 (retiring boxctl) aren't happening.


Claude-Session: https://claude.ai/code/session_01U8g3mHkS6JmtYVYc4AjcV4

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

⌂ 换网址