Skip to content

feat(fish): add clrc command for stable claude remote-control - #1204

Merged
shunkakinoki merged 2 commits into
mainfrom
feat/clrc-remote-control
Mar 19, 2026
Merged

feat(fish): add clrc command for stable claude remote-control#1204
shunkakinoki merged 2 commits into
mainfrom
feat/clrc-remote-control

Conversation

@shunkakinoki

@shunkakinoki shunkakinoki commented Mar 19, 2026

Copy link
Copy Markdown
Owner

Summary

  • Adds clrc fish abbreviation that runs claude remote-control by invoking node directly on the resolved cli.js inode (via realpath $(which claude))
  • When bun updates the claude package and writes a new file (new inode), the already-running session keeps its reference to the old inode and is unaffected
  • Fixes a pre-existing test failure in _ssh_add_github_test.fish where keychain was shadowed by erasing a fish function, but the real binary on PATH was still found by command -v; fix uses PATH filtering instead

Test plan

  • make fish-test passes 202/202
  • clrc — runs remote-control with a stable binary handle
  • clrc --name mysession --spawn worktree — args pass through correctly

Summary by cubic

Adds a clrc fish command that runs claude remote-control via node on the resolved claude path to keep sessions stable across bun upgrades. Also updates the OpenClaw Nix hydrate script to avoid context warnings and formats for treefmt.

  • New Features

    • clrc: runs node (realpath (which claude)) remote-control ... for stability; tests cover basic run and arg passthrough.
  • Bug Fixes

    • _ssh_add_github_test.fish: filter PATH so keychain is correctly treated as missing.
    • config/openclaw/default.nix: rewrite hydrate script with writeText/replaceStrings to avoid Nix context warnings; apply treefmt formatting.

Written for commit 44ad1a8. Summary will update on new commits.

Copilot AI review requested due to automatic review settings March 19, 2026 13:53
@mesa-dot-dev

mesa-dot-dev Bot commented Mar 19, 2026

Copy link
Copy Markdown

You do not have enough credits to review this pull request. Please purchase more credits to continue.

@coderabbitai

coderabbitai Bot commented Mar 19, 2026

Copy link
Copy Markdown
📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added a new command (clrc) for running Claude Code's remote-control functionality with argument forwarding support.
  • Tests

    • Added comprehensive tests for the new command and improved existing test setup for better reliability.

Walkthrough

This pull request modifies the OpenClaw configuration hydration logic by replacing the pkgs.replaceVars approach with a pkgs.writeText-based string substitution pipeline, adds a new Fish shell function to wrap Claude's remote-control subcommand, and introduces corresponding test coverage for the new function and test infrastructure changes.

Changes

Cohort / File(s) Summary
Nix Hydration Pipeline
config/openclaw/default.nix
Replaced hydrateScript construction from pkgs.replaceVars to custom pkgs.writeText pipeline with explicit @name@ placeholder substitution. Updated chromium and openclaw interpolation to explicit string forms and inlined template path.
Fish Remote Control Function
home-manager/programs/fish/functions/_clrc_function.fish
Added new _clrc_function that wraps Claude's remote-control subcommand by resolving the claude executable via realpath and invoking node with the resolved path and forwarded arguments.
Fish Function Tests
spec/fish/_clrc_function_test.fish, spec/fish/_ssh_add_github_test.fish
Added comprehensive test suite for _clrc_function with stubbed helpers and multiple test scenarios. Modified _ssh_add_github_test.fish to use PATH manipulation instead of function shadowing for cleaner test isolation.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

enhancement

Poem

🐰 A rabbit hops through hydration streams,
String substitution flows like dreams—
Fish functions wrapped with careful care,
Tests confirm it works with flair! 🚀

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat(fish): add clrc command for stable claude remote-control' accurately and concisely summarizes the primary change—adding a new fish command for stable claude remote-control.
Description check ✅ Passed The description comprehensively covers the changes, including the new clrc command, the session stability mechanism, and the test fix, with clear test results confirming the changeset.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/clrc-remote-control
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@mesa-dot-dev

mesa-dot-dev Bot commented Mar 19, 2026

Copy link
Copy Markdown

Mesa Description

TL;DR

Adds a clrc fish command for stable claude remote-control sessions that persist across bun package updates, and fixes a test related to keychain shadowing.

What changed?

  • home-manager/programs/fish/functions/_clrc_function.fish: New fish function _clrc_function to execute claude remote-control using node on the resolved claude binary path, ensuring stability when bun updates the claude symlink.
  • spec/fish/_clrc_function_test.fish: New test suite for _clrc_function, verifying correct node invocation with remote-control and argument passthrough.
  • spec/fish/_ssh_add_github_test.fish: Updated test for _ssh_add_github to remove directories containing the keychain binary from the PATH, providing a more accurate simulation of keychain's absence.

Description generated by Mesa. Update settings

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request enhances the development environment by introducing a robust clrc command for stable claude remote-control execution, ensuring uninterrupted operation despite bun package updates. It also includes refactorings of Nix hydration scripts to improve build stability and resolves a specific test failure related to keychain handling, alongside a minor configuration adjustment to suppress a home-manager warning.

Highlights

  • Stable Claude Remote-Control: Introduced a new clrc fish abbreviation that ensures the claude remote-control command uses a stable binary by resolving the cli.js inode directly via node, making it immune to bun updates.
  • Nix Hydration Script Refactor: Refactored Nix hydration scripts in config/ccs and config/openclaw to use pkgs.writeText and builtins.replaceStrings instead of pkgs.replaceVars to prevent builtins.toFile context warnings.
  • Test Fix for _ssh_add_github_test.fish: Corrected a pre-existing test failure in _ssh_add_github_test.fish by changing how keychain is handled in the test environment, now filtering it from the PATH instead of shadowing it with a fish function.
  • Home Manager Manual Warning Suppression: Suppressed a home-manager manual options.json generation warning by disabling manual.manpages.enable.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@shunkakinoki
shunkakinoki force-pushed the feat/clrc-remote-control branch from d0ac220 to 3347d35 Compare March 19, 2026 13:55

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a new clrc fish command for running Claude remote-control in a way that's resilient to updates, which is a nice enhancement. The implementation is straightforward and includes tests. The PR also includes some good refactoring of Nix files to use pkgs.writeText instead of pkgs.replaceVars, which aligns with modern Nix practices and avoids warnings. Additionally, a fix to a test for _ssh_add_github makes the test more robust. My main feedback is on the new test file for clrc, where the test structure could be simplified and made more robust. Overall, these are solid improvements.

Comment on lines +4 to +26
# ── basic: resolves symlink and runs node with remote-control ──
set log1 (mktemp)
set fake_cli (mktemp)

function which; echo $fake_cli; end
function realpath; echo $argv[1]; end
function node; echo "node" $argv >> $log1; end

_clrc_function

@test "calls node directly (not claude symlink)" (grep -c "^node" $log1) -ge 1
@test "passes remote-control subcommand" (grep -c "remote-control" $log1) -ge 1

# ── with args: passes through extra args ──────────────────────
set log2 (mktemp)
function node; echo "node" $argv >> $log2; end

_clrc_function --name mysession

@test "passes extra args through" (grep -c -- "--name" $log2) -ge 1
@test "still includes remote-control with args" (grep -c "remote-control" $log2) -ge 1

rm -f $log1 $log2 $fake_cli

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The test structure can be improved for better isolation and clarity. Redefining the node mock and using separate log files for each test case makes the test suite more complex and potentially brittle. A cleaner approach is to use a single set of mocks and a single log file, clearing the log between test cases. This improves readability and maintainability.

Additionally, the tests can be made more specific by checking for an exact count (-eq 1) instead of a minimum count (-ge 1), and it's good practice to clean up mocked functions after the tests complete.

# ── setup ─────────────────────────────────────────────────────
set -l log (mktemp)
set -l fake_cli (mktemp)

# Mock dependencies
function which; echo $fake_cli; end
function realpath; echo $argv[1]; end
function node; echo "node" $argv >> $log; end

# ── basic: resolves symlink and runs node with remote-control ──
_clrc_function
@test "calls node directly (not claude symlink)" (grep -c "^node" $log) -eq 1
@test "passes remote-control subcommand" (grep -c "remote-control" $log) -eq 1

> $log # Clear log for next test

# ── with args: passes through extra args ──────────────────────
_clrc_function --name mysession
@test "passes extra args through" (grep -c -- "--name" $log) -eq 1
@test "still includes remote-control with args" (grep -c "remote-control" $log) -eq 1

# ── teardown ──────────────────────────────────────────────────
functions -e which realpath node
rm -f $log $fake_cli

@shunkakinoki
shunkakinoki force-pushed the feat/clrc-remote-control branch 2 times, most recently from 23716c3 to 5d7c8b8 Compare March 19, 2026 13:58

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

2 issues found across 7 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="home-manager/programs/fish/functions/_clrc_function.fish">

<violation number="1" location="home-manager/programs/fish/functions/_clrc_function.fish:7">
P2: Resolve `claude` with a path-only lookup. `which` can be shadowed by a fish function, causing `realpath` to receive non-path output and breaking `clrc`.</violation>
</file>

<file name="spec/fish/_clrc_function_test.fish">

<violation number="1" location="spec/fish/_clrc_function_test.fish:9">
P2: This test never distinguishes `realpath (which claude)` from plain `which claude`, so it can pass even if the symlink-resolution behavior regresses.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

# keeps its reference to the old inode and is unaffected.
# Usage: clrc [<claude remote-control args...>]

set -l claude_real (realpath (which claude))

@cubic-dev-ai cubic-dev-ai Bot Mar 19, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: Resolve claude with a path-only lookup. which can be shadowed by a fish function, causing realpath to receive non-path output and breaking clrc.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At home-manager/programs/fish/functions/_clrc_function.fish, line 7:

<comment>Resolve `claude` with a path-only lookup. `which` can be shadowed by a fish function, causing `realpath` to receive non-path output and breaking `clrc`.</comment>

<file context>
@@ -0,0 +1,9 @@
+  # keeps its reference to the old inode and is unaffected.
+  # Usage: clrc [<claude remote-control args...>]
+
+  set -l claude_real (realpath (which claude))
+  node $claude_real remote-control $argv
+end
</file context>
Fix with Cubic

set fake_cli (mktemp)

function which; echo $fake_cli; end
function realpath; echo $argv[1]; end

@cubic-dev-ai cubic-dev-ai Bot Mar 19, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: This test never distinguishes realpath (which claude) from plain which claude, so it can pass even if the symlink-resolution behavior regresses.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At spec/fish/_clrc_function_test.fish, line 9:

<comment>This test never distinguishes `realpath (which claude)` from plain `which claude`, so it can pass even if the symlink-resolution behavior regresses.</comment>

<file context>
@@ -0,0 +1,26 @@
+set fake_cli (mktemp)
+
+function which; echo $fake_cli; end
+function realpath; echo $argv[1]; end
+function node; echo "node" $argv >> $log1; end
+
</file context>
Fix with Cubic

Resolves bun-update staleness by invoking node directly on the resolved
cli.js inode, so running sessions survive bun replacing the binary.

Also fixes _ssh_add_github test to use PATH filtering instead of erasing
a fish function (which didn't hide the real keychain binary on PATH).
@shunkakinoki
shunkakinoki force-pushed the feat/clrc-remote-control branch from 5d7c8b8 to 45acd9d Compare March 19, 2026 13:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds a Fish helper for running claude remote-control via a stable file handle (for resilience across bun updates), and updates Fish tests + Nix hydration scripts to reduce warnings and fix a test edge case.

Changes:

  • Add _clrc_function Fish function and a new spec to validate argument passthrough and node invocation.
  • Fix _ssh_add_github test setup by filtering keychain out of PATH rather than trying to shadow/erase a function.
  • Replace pkgs.replaceVars with writeText + builtins.replaceStrings for hydration scripts; suppress a Home Manager manual warning.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
spec/fish/_ssh_add_github_test.fish Adjusts test setup to remove keychain from PATH reliably.
spec/fish/_clrc_function_test.fish Adds coverage for _clrc_function behavior (node invocation + arg passthrough).
home-manager/programs/fish/functions/_clrc_function.fish Implements _clrc_function to resolve claude’s real path and invoke node ... remote-control.
home-manager/default.nix Disables Home Manager manpages generation (comment says options.json warning suppression).
config/openclaw/default.nix Reworks hydration script generation using writeText + replaceStrings.
config/ccs/default.nix Reworks hydration script generation using writeText + replaceStrings.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +8 to +10
function which; echo $fake_cli; end
function realpath; echo $argv[1]; end
function node; echo "node" $argv >> $log1; end

# ── with args: passes through extra args ──────────────────────
set log2 (mktemp)
function node; echo "node" $argv >> $log2; end
Comment on lines 35 to 40
Comment thread config/ccs/default.nix
Comment on lines 12 to 17
Comment thread home-manager/default.nix
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

@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

🧹 Nitpick comments (1)
spec/fish/_clrc_function_test.fish (1)

14-15: Strengthen the “not claude symlink” assertion to match intent.

Current checks only prove node ran and remote-control is present. Add an explicit assertion that the resolved path ($fake_cli) is passed to node.

✅ Suggested test additions
 `@test` "calls node directly (not claude symlink)" (grep -c "^node" $log1) -ge 1
 `@test` "passes remote-control subcommand" (grep -c "remote-control" $log1) -ge 1
+@test "passes resolved claude path to node" (grep -F -c -- "$fake_cli" $log1) -ge 1
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@spec/fish/_clrc_function_test.fish` around lines 14 - 15, Update the "calls
node directly (not claude symlink)" test to assert that the resolved CLI path
($fake_cli) is passed to node: instead of only checking for a "^node" line in
$log1, add/replace an assertion that the node invocation in $log1 contains the
literal $fake_cli (e.g., grep for $fake_cli in $log1) so the test ensures node
was invoked with the resolved $fake_cli path; keep the existing "passes
remote-control subcommand" check unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@home-manager/programs/fish/functions/_clrc_function.fish`:
- Around line 7-8: The current _clrc_function.fish computes claude_real with
"set -l claude_real (realpath (which claude))" then blindly runs "node
$claude_real remote-control $argv", which will call node without a script if
which/realpath fail; update _clrc_function.fish to guard after computing
claude_real with "if test -z \"$claude_real\"; echo 'Error: claude not found'
>&2; return 1; end" (or similar) so you early-return on missing/empty
claude_real, keeping the descriptive stderr message; also add spec tests
covering both failure modes (simulate missing claude and failing realpath)
asserting the function returns non-zero and emits the error message.

---

Nitpick comments:
In `@spec/fish/_clrc_function_test.fish`:
- Around line 14-15: Update the "calls node directly (not claude symlink)" test
to assert that the resolved CLI path ($fake_cli) is passed to node: instead of
only checking for a "^node" line in $log1, add/replace an assertion that the
node invocation in $log1 contains the literal $fake_cli (e.g., grep for
$fake_cli in $log1) so the test ensures node was invoked with the resolved
$fake_cli path; keep the existing "passes remote-control subcommand" check
unchanged.
🪄 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: 6fc83306-061d-4d1e-aab0-685bc0dcd85d

📥 Commits

Reviewing files that changed from the base of the PR and between e429ecf and 44ad1a8.

📒 Files selected for processing (4)
  • config/openclaw/default.nix
  • home-manager/programs/fish/functions/_clrc_function.fish
  • spec/fish/_clrc_function_test.fish
  • spec/fish/_ssh_add_github_test.fish

Comment on lines +7 to +8
set -l claude_real (realpath (which claude))
node $claude_real remote-control $argv

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect current clrc resolution flow and related tests.
rg -n -C3 'which claude|realpath|node \$claude_real remote-control' home-manager/programs/fish/functions/_clrc_function.fish
rg -n -C3 '_clrc_function|remote-control|which|realpath|node' spec/fish/_clrc_function_test.fish

Repository: shunkakinoki/dotfiles

Length of output: 1200


🏁 Script executed:

#!/bin/bash
# Verify Fish shell behavior for failed command substitution
# Check if there are similar error-handling patterns elsewhere in the codebase

# 1. Test Fish behavior when which fails
fish -c 'which nonexistent_command_xyz; echo "Exit code: $status"'

# 2. Look for other error handling patterns in Fish functions
fd -t f '\.fish$' home-manager/programs/fish/functions/ -x grep -l 'if.*test' {} \; | head -5
rg -n 'if.*test.*-z|if.*which|if.*realpath' home-manager/programs/fish/functions/ -A 2 | head -30

# 3. Check spec file for error case tests
cat spec/fish/_clrc_function_test.fish

Repository: shunkakinoki/dotfiles

Length of output: 3156


Add guards for which and realpath failures before invoking node.

If which claude or realpath fail, $claude_real becomes empty and Line 8 executes node remote-control $argv (missing the script path). The codebase establishes a consistent error-handling pattern elsewhere (e.g., _ocxeh_function.fish, _tsk_function.fish) using if test -z "$var" checks with early returns. Apply the same pattern here. Additionally, the spec file has no tests for error cases; the proposed fix should include tests for missing claude and realpath failure scenarios.

Proposed fix
-  set -l claude_real (realpath (which claude))
-  node $claude_real remote-control $argv
+  set -l claude_bin (which claude 2>/dev/null)
+  if test -z "$claude_bin"
+    echo "clrc: claude not found in PATH" >&2
+    return 127
+  end
+
+  set -l claude_real (realpath $claude_bin 2>/dev/null)
+  if test -z "$claude_real"
+    echo "clrc: failed to resolve claude path: $claude_bin" >&2
+    return 1
+  end
+
+  node $claude_real remote-control $argv
📝 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
set -l claude_real (realpath (which claude))
node $claude_real remote-control $argv
set -l claude_bin (which claude 2>/dev/null)
if test -z "$claude_bin"
echo "clrc: claude not found in PATH" >&2
return 127
end
set -l claude_real (realpath $claude_bin 2>/dev/null)
if test -z "$claude_real"
echo "clrc: failed to resolve claude path: $claude_bin" >&2
return 1
end
node $claude_real remote-control $argv
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@home-manager/programs/fish/functions/_clrc_function.fish` around lines 7 - 8,
The current _clrc_function.fish computes claude_real with "set -l claude_real
(realpath (which claude))" then blindly runs "node $claude_real remote-control
$argv", which will call node without a script if which/realpath fail; update
_clrc_function.fish to guard after computing claude_real with "if test -z
\"$claude_real\"; echo 'Error: claude not found' >&2; return 1; end" (or
similar) so you early-return on missing/empty claude_real, keeping the
descriptive stderr message; also add spec tests covering both failure modes
(simulate missing claude and failing realpath) asserting the function returns
non-zero and emits the error message.

@shunkakinoki
shunkakinoki merged commit 9ec6ecf into main Mar 19, 2026
33 checks passed
@shunkakinoki
shunkakinoki deleted the feat/clrc-remote-control branch March 19, 2026 15:00
@coderabbitai coderabbitai Bot mentioned this pull request Apr 18, 2026
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.

2 participants