Skip to content

feat(install): Claude bin launchers — absolute-path workers + per-account wrappers + guard - #51

Merged
webdevtodayjason merged 3 commits into
mainfrom
feat/claude-bin-launchers
Jun 2, 2026
Merged

feat(install): Claude bin launchers — absolute-path workers + per-account wrappers + guard#51
webdevtodayjason merged 3 commits into
mainfrom
feat/claude-bin-launchers

Conversation

@webdevtodayjason

@webdevtodayjason webdevtodayjason commented Jun 1, 2026

Copy link
Copy Markdown
Owner

Reconciles main with the A1/guard launcher work that's been deployed live since 2026-05-29 but never landed on main. Clean superset of origin/main (#49) — 3 commits, 0 behind, no rebase.

What's in here (two co-committed stories — both already live, not split)

  1. Claude bin launchers (the headline):
    • 12fb595 feat(install): launch Claude by absolute path (CLAUDE_BIN); per-account wrapper scripts (claude-jason / claude-titanium / claude-semfreak) in ~/.local/bin.
    • 7651ffd fix(install): bare claude launches the claude-use-selected account (guard).
  2. Local-AI chore (rode along on the same branch):
    • 2a52db5 chore(local-ai): consolidate local models to LM Studio; cognee default → qwen3.5-9b.

Touches only lib/migrate.sh, lib/cognee.sh, RESUME.md.

Safety

Release

No VERSION bump in this PR (landing code ≠ cutting a release, per the one-story-per-tag discipline). Tag v3.3.13 after merge if desired.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Documentation

    • Updated operational documentation with current development status, local environment configuration details, system component states, and prioritized action items.
  • Chores

    • Updated default language model selection for code analysis operations.
    • Refined command launcher routing behavior and wrapper script handling for improved consistency.

webdevtodayjason and others added 3 commits May 28, 2026 22:04
…t → qwen3.5-9b

Tonight's hard-reboots on the M5 Max laptop were NOT RAM (swap 0) or claude-mem —
they were too many concurrent local-GPU model engines: oMLX (cognee's 26B on :8000)
+ LM Studio reload-thrash + Cotypist + Grok (new today). A year of 8-16 cloud-API
Claude terminals never crashed; heavy local MLX inference was the new variable.

- lib/cognee.sh: default reviewer model 26B → qwen/qwen3.5-9b; comment explains
  LM Studio is the single local endpoint and why oMLX was retired. (Base default
  was already :1234; live plist updated + oMLX `brew services stop`'d separately.)
- RESUME.md: corrected lockup root-cause narrative; documented the LM-Studio-only
  consolidation, the "one local engine" rule, and the offload-to-M3/DGX idea.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ripts

Generated shell-aliases.sh used `command claude` (PATH-relative) and
per-account shell *aliases* — both broke in the split-brain PATH: the
tmux/launchd PATH differs from the interactive shell, and aliases vanish
in non-interactive shells, scripts, and cron.

- shell-aliases.sh now defines CLAUDE_BIN (default ~/.local/bin/claude,
  overridable); the bare-`claude` account guard runs "$CLAUDE_BIN".
- claude-jason/titanium/semfreak are now standalone exec wrapper scripts
  in ~/.local/bin (work in scripts/cron/non-interactive), each pinning its
  CLAUDE_CONFIG_DIR and exec'ing the native binary by absolute path.
- claude-use stays a function (it mutates the shell's env).

Plan item A1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The guard re-prompted "Pick an account first" even after `claude-use jason`
set CLAUDE_CONFIG_DIR — defeating the point of claude-use. Now: if an account
is selected (CLAUDE_CONFIG_DIR set), bare `claude` launches it via $CLAUDE_BIN;
only the unset (master ~/.claude) case still prompts. Subcommand/flag
passthrough unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 1, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR updates operational documentation in RESUME.md with concrete current state and pending decisions across v3 and v4 development tracks; updates the default LLM model for Cognee code review from gemma to qwen3.5; and refactors the generated Claude account-routing dispatcher in lib/migrate.sh from shell aliases to a canonical CLAUDE_BIN variable with guard-based dispatch logic.

Changes

Operational Updates & Claude Routing Refactor

Layer / File(s) Summary
Current Operational Status
RESUME.md
Converted from placeholder template to detailed operational log: documents v3 bash/TypeScript and v4 Rust development tracks; records local-AI stack configuration (LM Studio with specific services stopped/disabled); expands next action, polish, and nit lists into explicit checklists; lists pending operational decisions; prioritizes files to open; and confirms no P0 status with troubleshooting guidance.
Default LLM Model Configuration
lib/cognee.sh
Updated default Cognee reviewer model to qwen/qwen3.5-9b (overridable via SUBCTL_COGNEE_LLM_MODEL environment variable), with adjusted comments describing the new default.
Claude Account Routing Architecture
lib/migrate.sh
Refactored generated shell-aliases.sh dispatcher: introduces canonical CLAUDE_BIN variable pointing to $HOME/.local/bin/claude; replaces shell aliases with guard-based claude() function that checks CLAUDE_CONFIG_DIR (set by claude-use to select account); if config is set, directly invokes CLAUDE_BIN with passthrough args; if not set, prompts user to pick an account and returns failure. Updated per-account launcher wrappers in ~/.local/bin to exec env CLAUDE_CONFIG_DIR=... "$CLAUDE_BIN" "$@".

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • webdevtodayjason/subctl#38: Adjusts bin/claude-* shim behavior to resolve/exec the sibling subctl dispatcher instead of relying on $PATH, complementing the routing dispatch refactoring in this PR.
  • webdevtodayjason/subctl#48: Routes claude-use, claude-whoami, and claude-accounts through explicit v3 subctl resolver to avoid PATH collisions, working alongside this PR's dispatcher guard logic for account/config resolution.

Poem

🐰 A resume reborn, no longer a shell,
Qwen whispers wisdom where Gemma once dwelt,
Claude's account routing now guards with a grace,
From aliases tangled to binaries in place.
The tracks converge clarity—v3 and v4 aligned.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly describes the main changes: adding Claude bin launchers with absolute-path workers, per-account wrappers, and a guard mechanism. It directly aligns with the primary feature work in lib/migrate.sh and reflects the core objective of the PR.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/claude-bin-launchers

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/migrate.sh (1)

277-299: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard only the bare interactive launch.

This allowlist blocks every unlisted Claude verb when CLAUDE_CONFIG_DIR is unset, even though the surrounding comment says the interactive launch is the only guarded path. Any new or less-common subcommand will fail on the default account until this list is kept in sync.

Suggested simplification
 claude() {
-  # Pass-through commands/flags. Interactive REPL is the ONLY thing we guard.
-  case "${1:-}" in
-    update|doctor|migrate-installer|setup-token|mcp|config|ultrareview|""|"") ;;
-  esac
   if [[ $# -gt 0 ]]; then
-    case "$1" in
-      update|doctor|migrate-installer|setup-token|mcp|config|ultrareview \
-      |--version|-v|--help|-h|-p|--print|--resume|--continue|-c|-r)
-        "$CLAUDE_BIN" "$@"
-        return $?
-        ;;
-    esac
+    "$CLAUDE_BIN" "$@"
+    return $?
   fi
   # An account is already selected for this shell (via claude-use) — just
   # launch it; no need to re-prompt.
   if [[ -n "${CLAUDE_CONFIG_DIR:-}" ]]; then
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/migrate.sh` around lines 277 - 299, The current allowlist in the initial
case block prevents any unlisted Claude subcommand from running when
CLAUDE_CONFIG_DIR is unset; instead, only the bare interactive launch should be
guarded. Replace the allowlist logic in the block that checks $# with a simple
unconditional forward: if [[ $# -gt 0 ]]; then "$CLAUDE_BIN" "$@"; return $?; fi
so any provided args are passed through to CLAUDE_BIN; retain the subsequent
CLAUDE_CONFIG_DIR check and the interactive prompt (claude-whoami, claude-use,
claude-jason) as-is and update the comment to say “Guard only the bare
interactive launch.”
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lib/migrate.sh`:
- Around line 312-318: The generated wrapper currently embeds
CLAUDE_CONFIG_DIR="$wcfg" which preserves a leading '~' instead of expanding it;
before writing the here-doc, expand tilde for wcfg (e.g. compute an expanded
variable like expanded_wcfg by replacing a leading ~ with $HOME or using eval
echo "$wcfg") and then write CLAUDE_CONFIG_DIR="$expanded_wcfg" into the
wrapper; update the code that generates the file (the loop using walias,
wprovider, wemail, wcfg and the here-doc that writes to "$bindir/$walias") to
reference the expanded variable instead of the raw wcfg.

---

Outside diff comments:
In `@lib/migrate.sh`:
- Around line 277-299: The current allowlist in the initial case block prevents
any unlisted Claude subcommand from running when CLAUDE_CONFIG_DIR is unset;
instead, only the bare interactive launch should be guarded. Replace the
allowlist logic in the block that checks $# with a simple unconditional forward:
if [[ $# -gt 0 ]]; then "$CLAUDE_BIN" "$@"; return $?; fi so any provided args
are passed through to CLAUDE_BIN; retain the subsequent CLAUDE_CONFIG_DIR check
and the interactive prompt (claude-whoami, claude-use, claude-jason) as-is and
update the comment to say “Guard only the bare interactive launch.”
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7b81c27e-7ad6-4ba9-acae-0b43be7e0c3f

📥 Commits

Reviewing files that changed from the base of the PR and between cc3b981 and 7651ffd.

📒 Files selected for processing (3)
  • RESUME.md
  • lib/cognee.sh
  • lib/migrate.sh

Comment thread lib/migrate.sh
Comment on lines +312 to +318
while IFS=$'\t' read -r walias wprovider wemail wcfg wdesc; do
[[ "$wprovider" == "claude" ]] || continue
cat > "$bindir/$walias" <<WRAP
#!/usr/bin/env bash
# Auto-generated by subctl — per-account claude launcher. Re-run \`subctl install\`.
exec env CLAUDE_CONFIG_DIR="$wcfg" "\${CLAUDE_BIN:-\$HOME/.local/bin/claude}" "\$@"
WRAP

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
env CLAUDE_CONFIG_DIR="~/.claude-test" bash -lc 'printf "%s\n" "$CLAUDE_CONFIG_DIR"'

Repository: webdevtodayjason/subctl

Length of output: 199


Expand ~ before embedding CLAUDE_CONFIG_DIR into the generated wrapper

In lib/migrate.sh, the wrapper sets CLAUDE_CONFIG_DIR="$wcfg" (quoted), so Bash won’t expand a leading ~. If wcfg comes from config as ~/.claude-*, the launcher will pass the literal ~ to claude.

Suggested fix
  while IFS=$'\t' read -r walias wprovider wemail wcfg wdesc; do
    [[ "$wprovider" == "claude" ]] || continue
+    wcfg="${wcfg/#\~/$HOME}"
    cat > "$bindir/$walias" <<'WRAP'
 #!/usr/bin/env bash
 # Auto-generated by subctl — per-account claude launcher. Re-run `subctl install`.
 exec env CLAUDE_CONFIG_DIR="$wcfg" "${CLAUDE_BIN:-$HOME/.local/bin/claude}" "$@"
 WRAP
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
while IFS=$'\t' read -r walias wprovider wemail wcfg wdesc; do
[[ "$wprovider" == "claude" ]] || continue
cat > "$bindir/$walias" <<WRAP
#!/usr/bin/env bash
# Auto-generated by subctl — per-account claude launcher. Re-run \`subctl install\`.
exec env CLAUDE_CONFIG_DIR="$wcfg" "\${CLAUDE_BIN:-\$HOME/.local/bin/claude}" "\$@"
WRAP
while IFS=$'\t' read -r walias wprovider wemail wcfg wdesc; do
[[ "$wprovider" == "claude" ]] || continue
wcfg="${wcfg/#\~/$HOME}"
cat > "$bindir/$walias" <<'WRAP'
#!/usr/bin/env bash
# Auto-generated by subctl — per-account claude launcher. Re-run `subctl install`.
exec env CLAUDE_CONFIG_DIR="$wcfg" "${CLAUDE_BIN:-$HOME/.local/bin/claude}" "$@"
WRAP
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/migrate.sh` around lines 312 - 318, The generated wrapper currently
embeds CLAUDE_CONFIG_DIR="$wcfg" which preserves a leading '~' instead of
expanding it; before writing the here-doc, expand tilde for wcfg (e.g. compute
an expanded variable like expanded_wcfg by replacing a leading ~ with $HOME or
using eval echo "$wcfg") and then write CLAUDE_CONFIG_DIR="$expanded_wcfg" into
the wrapper; update the code that generates the file (the loop using walias,
wprovider, wemail, wcfg and the here-doc that writes to "$bindir/$walias") to
reference the expanded variable instead of the raw wcfg.

@webdevtodayjason
webdevtodayjason merged commit c98bcf3 into main Jun 2, 2026
1 of 2 checks passed
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