Skip to content

Add onctl claude: Claude Code on a box, ported from boxctl - #1173

Merged
cdalar merged 1 commit into
mainfrom
feat/onctl-claude
Oct 4, 2026
Merged

cdalar merged 1 commit into
mainfrom
feat/onctl-claude

Conversation

@cdalar

@cdalar cdalar commented Oct 4, 2026

Copy link
Copy Markdown
Owner

Rollout step 3 of docs/plans/boxes-provider.md. boxctl's claude command moves here with its tests, running on the boxes provider:

onctl claude                          # create or reattach the project's box, Claude in tmux
onctl claude --prompt "fix the flaky test" --detach
onctl claude --task auth              # a parallel task: its own worktree, branch and Claude
onctl claude ls                       # every session for this project
onctl claude fetch / push             # the work as git: box/* branches, box/wip
onctl claude --handoff <session-id>   # continue a local Claude Code session on the box
onctl claude login / logout           # lend your Claude login to every box

What changed in the port

  • Boxes only: onctl claude always uses boxes, since it needs the claude-agent image's tools and the tunnel. Any other -p is refused.

  • --prompt lost its -p shorthand, which is onctl's global --provider. Cobra would otherwise panic at startup.

  • New local state, with boxctl's still read: state now lives in ~/.onctl/claude, and boxctl's is still read, so nothing has to be redone:

    • its ssh key (shared with the Claude Code plugin);
    • its Claude token file and macOS Keychain entry;
    • BOXCTL_GITHUB_TOKEN, next to the new ONCTL_GITHUB_TOKEN.

    onctl claude logout clears both.

  • Nothing changes on the box: /root/.boxctl, /run/boxctl, refs/boxctl/wip and BOXCTL_GH_SOCKET keep their names, so existing boxes and the current claude-agent image keep working.

  • Uses onctl's own pieces: the providerboxes client (plus SetIdleTTL) and onctl ssh-proxy -p boxes. sshProxyHost is now shared with ssh-proxy.

Tests

  • boxctl's claude tests, ported, with expectations updated to "onctl".
  • A test that the claude subcommands are recognized.
  • go test -race -shuffle=on ./... passed 3 times in a row; golangci-lint is clean.

Live, against boxctl.io (throwaway project and box, destroyed afterwards):

  • onctl claude --detach created the box, copied the project, installed Claude Code 2.1.289 and started Claude in tmux:
    • the commit and the uncommitted change arrived;
    • the git-ignored .env was left out.
  • onctl claude ls showed the session.
  • A commit made on the box came back as box/main via onctl claude fetch.
  • --task t1 made its own worktree and branch; ls showed both sessions.
  • onctl claude push feature sent a local branch to the box.

Not exercised live: interactive attach with GitHub forwarding, --handoff, and onctl claude login. These need a terminal and your Claude token. Their code paths are unchanged from boxctl and covered by its unit tests.

Next: step 4, moving the Claude Code plugin here (/onctl:on…), then step 5, retiring boxctl.

🤖 Generated with Claude Code

https://claude.ai/code/session_01U8g3mHkS6JmtYVYc4AjcV4

Rollout step 3 of docs/plans/boxes-provider.md. boxctl's claude command
and everything under it -- --task worktrees and --own-box, --handoff of a
local session, ls, fetch/push with box/wip, login/logout for the Claude
token, and --github forward|store|off -- moves here with its tests,
running on the boxes provider through onctl's providerboxes client and
onctl ssh-proxy.

onctl claude always uses boxes (it needs the claude-agent image's tools
and the tunnel); another -p is refused. --prompt lost its -p shorthand,
which is onctl's global --provider.

Local state moves to ~/.onctl/claude and keeps reading boxctl's: its ssh
key (also the Claude Code plugin's), its Claude token file and Keychain
entry, and BOXCTL_GITHUB_TOKEN beside the new ONCTL_GITHUB_TOKEN. Logging
out clears both. Everything on the box -- /root/.boxctl, /run/boxctl,
refs/boxctl/wip, BOXCTL_GH_SOCKET -- is unchanged, so existing boxes and
the current claude-agent image keep working.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U8g3mHkS6JmtYVYc4AjcV4
@cdalar
cdalar enabled auto-merge October 4, 2026 22:05
@cdalar
cdalar merged commit 9e91562 into main Oct 4, 2026
12 checks passed
@codecov

codecov Bot commented Oct 4, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 33.11331% with 608 lines in your changes missing coverage. Please review.
✅ Project coverage is 39.07%. Comparing base (5138508) to head (78c2c07).
⚠️ Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
cmd/claude.go 19.85% 226 Missing ⚠️
cmd/claudeauth.go 3.40% 85 Missing ⚠️
cmd/claudecopy.go 49.67% 77 Missing ⚠️
cmd/claudegit.go 31.53% 76 Missing ⚠️
cmd/claudels.go 11.84% 67 Missing ⚠️
cmd/claudegithub.go 53.46% 47 Missing ⚠️
cmd/claudesession.go 75.90% 20 Missing ⚠️
internal/providerboxes/client.go 0.00% 5 Missing ⚠️
cmd/root.go 50.00% 4 Missing ⚠️
cmd/sshproxy.go 50.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1173      +/-   ##
==========================================
- Coverage   39.83%   39.07%   -0.76%     
==========================================
  Files          61       68       +7     
  Lines        6384     7296     +912     
==========================================
+ Hits         2543     2851     +308     
- Misses       3841     4445     +604     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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

⌂ 换网址