Skip to content

HMD Optical Hand tracking and MANUS automatic installation#235

Open
timvw-manusvr wants to merge 16 commits intoNVIDIA:mainfrom
manusvr:manus/hmd-hand-tracking
Open

HMD Optical Hand tracking and MANUS automatic installation#235
timvw-manusvr wants to merge 16 commits intoNVIDIA:mainfrom
manusvr:manus/hmd-hand-tracking

Conversation

@timvw-manusvr
Copy link
Copy Markdown

@timvw-manusvr timvw-manusvr commented Mar 10, 2026

HMD Optical Hand Tracking

Summary

This PR adds support for using the HMD's built-in optical hand tracking (via the XR_MNDX_xdev_space extension) as the wrist position source when using Manus gloves, along with automated installation scripts and improved documentation.

Changes

HMD optical hand tracking wrist source (XR_MNDX_xdev_space)

  • At initialization the plugin now attempts to load the XR_MNDX_xdev_space and XR_EXT_hand_tracking extension function pointers. If both are available, it creates two native XrHandTrackerEXT handles backed by the HMD's optical tracking ("Head Device (0)" = left, "Head Device (1)" = right).
  • inject_hand_data() now auto-selects the wrist pose source: HMD optical tracking when available (m_xdev_available == true), falling back silently to controller aim-pose + wrist offset when not.
  • A startup log line reports which source is active: [Manus] Initialized with wrist source: HandTracking or Controllers.
  • New private methods added: initialize_xdev_hand_trackers(), cleanup_xdev_hand_trackers(), update_xdev_hand(), get_controller_wrist_pose().
  • m_handles is now stored as a member so it can be reused across the new helper methods without fetching it repeatedly.
  • HandTracker is now registered alongside ControllerTracker in the DeviceIOSession.
  • XR_MNDX_xdev_space is requested as a required extension at session creation time.
  • Injector lifecycle simplified: injectors are created once at init rather than being lazily recreated on glove reconnect; glove-disconnect no longer destroys them.
  • All std::cout log messages prefixed with [Manus] for consistent filtering.

manus_hand_tracker_printer.cpp

  • All console output prefixed with [Manus] to match the plugin log format.

install_manus.sh (new file)

All-in-one installation script:

  1. Prompts whether to install Integrated-only or Integrated + Remote (gRPC) dependencies.
  2. Installs required system packages.
  3. Automatically downloads MANUS Core SDK v3.1.1 from the Manus CDN.
  4. Extracts and places the SDK into the correct directory layout.
  5. Builds the plugin from the TeleopCore root.

install-dependencies.sh (new file)

Full dependency installer for the Remote mode:

  • Installs GCC-11 (with fallback PPA/repo for systems where it's not available, since GCC-12+ is incompatible with gRPC v1.28.1).
  • Clones and builds gRPC v1.28.1 and protobuf from source.
  • Applies an abseil-cpp patch required for GCC 11+ compatibility.
  • Configures global install via ldconfig.

README.md

  • Added Automated Installation section documenting install_manus.sh.
  • Retained a Manual Installation section for advanced users, updated with current doc links.
  • Added CloudXR environment setup steps (setup_cloudxr_env.sh, run_cloudxr.sh) as a prerequisite to running the plugin.
  • Added a new section explaining the two wrist tracking modes: Quest 3 controller adapters vs HMD optical hand tracking, and noted that dynamic switching is automatic.
  • Expanded troubleshooting section: SDK download failures, CloudXR runtime errors, and USB udev permission reload steps.

Summary by CodeRabbit

Release Notes

  • New Features

    • Manus hand tracker printer now displays real-time 3D hand skeleton visualization alongside terminal output.
    • Added automated installation script for Manus plugin with built-in dependency management and SDK setup.
    • New Isaac Lab integration script for streamlined teleoperation agent execution.
  • Documentation

    • Added comprehensive Manus plugin installation and runtime guide with troubleshooting sections.
    • Documented cloud XR environment configuration requirements and controller-based hand tracking positioning.
  • Chores

    • Added USB device permission rules for Manus hardware.

Copilot AI review requested due to automatic review settings March 10, 2026 13:12
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 10, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This pull request integrates XDev hand tracking with optional OpenXR extension probing into the Manus hand tracking plugin, adds a Vulkan-based real-time hand skeleton visualizer, and introduces automated SDK installation and runtime environment setup workflows.

Changes

Cohort / File(s) Summary
Documentation & Index
docs/source/device/index.rst, docs/source/device/manus.rst, src/plugins/manus/README.md
Comprehensive documentation updates including new Sphinx page covering prerequisites, automated/manual installation, runtime setup with CloudXR environment variables, wrist-pose positioning behavior, and troubleshooting guidance; README restructured to explain automated installation via script and updated build/run instructions.
Installation & Build Infrastructure
src/plugins/manus/install_manus.sh, src/plugins/manus/70-manus-hid.rules, src/plugins/manus/tools/CMakeLists.txt
New automated installer script with SDK download, SHA-256 verification, dependency installation, and plugin build; udev rules for HID device permissions; CMake configuration extended to link Vulkan and X11 libraries.
Core Plugin Implementation
src/plugins/manus/inc/core/manus_hand_tracking_plugin.hpp, src/plugins/manus/core/manus_hand_tracking_plugin.cpp
OpenXR extension probing and conditional HandTracker creation; XDev lifecycle management with native hand tracker initialization/cleanup; wrist-pose acquisition logic with XDev-primary fallback to controller poses; cached node topology and joint tracking state; new public accessor methods for left/right node info.
Visualization & Tooling
src/plugins/manus/tools/manus_hand_visualizer.hpp, src/plugins/manus/tools/manus_hand_tracker_printer.cpp
New header-only Vulkan-based hand visualizer rendering dual orthographic views (top/side) with Xlib window management and real-time skeleton projection; printer tool updated to launch visualizer in detached background thread and standardize console output with [Manus] prefix.
Runtime Scripts
scripts/run_isaac_lab.sh
New entrypoint script sourcing CloudXR environment setup, validating OpenXR/Isaac Lab paths, resolving Python virtual environments, and invoking Isaac Lab with fixed teleoperation parameters and hand-tracking device configuration.

Sequence Diagram

sequenceDiagram
    actor User
    participant Printer as Printer CLI
    participant Plugin as Manus Plugin
    participant XR as OpenXR
    participant XDev as XDev System
    participant Manus as Manus SDK
    participant Vis as Vulkan Visualizer

    User->>Printer: Launch manus_hand_tracker_printer
    Printer->>Plugin: Create tracker instance
    Plugin->>XR: Probe extensions (XR_EXT_hand_tracking, XR_MNDX_xdev_space)
    Plugin->>Manus: Connect to Manus SDK
    Plugin->>XDev: Initialize native hand trackers (if advertised)
    XDev->>Plugin: Return tracker handles
    Plugin-->>Printer: Tracker ready
    Printer->>Vis: Launch visualizer thread
    Printer-->>User: Ready for input

    loop Per-frame
        Plugin->>Manus: Fetch glove skeleton data
        Plugin->>XDev: Update hand poses (if available)
        alt XDev pose valid
            Plugin->>Plugin: Use XDev wrist pose
        else
            Plugin->>XR: Fallback to controller pose
        end
        Plugin->>XR: Inject hand joint data
        Printer->>Plugin: Retrieve left/right node info
        Printer-->>User: Print joint data
        Vis->>Plugin: Fetch node topology & poses
        Vis->>Vis: Project 3D skeleton to 2D (4-view layout)
        Vis->>Vis: Render with Vulkan
        Vis-->>User: Display hand visualization
    end

    User->>Printer: Press stop key
    Printer->>Plugin: Shutdown
    Plugin->>XDev: Cleanup hand trackers
    Plugin->>XR: Cleanup session
    Vis->>Vis: Destroy Vulkan resources
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Poem

🐰 With XDev hands and Vulkan's glow,
Real-time skeletons now show!
OpenXR probing, features dance,
Fallback poses, smart stance—
From gloves to frames, data flows bright,
Teleop hands, now in sight! 🖐️✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 52.94% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the two main changes in the PR: adding HMD optical hand tracking support and MANUS automatic installation, both of which are primary objectives reflected in the code changes and documentation updates.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds support for using the HMD's built-in optical hand tracking (via the XR_MNDX_xdev_space extension) as the wrist position source when using Manus gloves, alongside two new automated installation scripts and expanded documentation.

Changes:

  • Adds initialize_xdev_hand_trackers() / cleanup_xdev_hand_trackers() / update_xdev_hand() / get_controller_wrist_pose() to the plugin, with automatic fallback from HMD optical tracking to controller-based wrist positioning.
  • Introduces two new shell scripts (install_manus.sh, install-dependencies.sh) for end-to-end automated installation including SDK download, dependency setup (with optional gRPC), and plugin build.
  • Updates README.md with automated installation instructions, CloudXR setup steps, a new section on the two wrist-tracking modes, and an expanded troubleshooting guide.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
src/plugins/manus/core/manus_hand_tracking_plugin.cpp Adds XDev/hand tracking initialization, wrist-source auto-selection, and simplifies injector lifecycle
src/plugins/manus/inc/core/manus_hand_tracking_plugin.hpp Adds new private methods, XDev handle/function-pointer members, and HandTracker member
src/plugins/manus/tools/manus_hand_tracker_printer.cpp Adds [Manus] prefix to all console output lines
src/plugins/manus/install_manus.sh New all-in-one installation and build script
src/plugins/manus/install-dependencies.sh New script for building gRPC v1.28.1 and system dependencies
src/plugins/manus/README.md Expanded with automated install, CloudXR setup, tracking modes, and troubleshooting

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

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 9

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/plugins/manus/core/manus_hand_tracking_plugin.cpp`:
- Around line 99-100: The printed diagnostic incorrectly says "Z-up" while the
coordinate system is actually configured with up = AxisPolarity_PositiveY;
update the log string printed before calling
CoreSdk_InitializeCoordinateSystemWithVUH(t_VUH, true) (the std::cout line) to
reflect "Y-up, right-handed, meters" so the diagnostic matches the SDK
configuration (referencing AxisPolarity_PositiveY and the call to
CoreSdk_InitializeCoordinateSystemWithVUH).
- Around line 507-514: The code currently treats a wrist pose as "valid" in
update_xdev_hand by checking XR_SPACE_LOCATION_POSITION_VALID_BIT and
XR_SPACE_LOCATION_ORIENTATION_VALID_BIT but does not ensure the pose is actively
tracked; change the logic in update_xdev_hand where wrist is read (using
joint_locations[XR_HAND_JOINT_WRIST_EXT] and wrist.locationFlags) to also check
XR_SPACE_LOCATION_POSITION_TRACKED_BIT and
XR_SPACE_LOCATION_ORIENTATION_TRACKED_BIT before returning success/setting
out_wrist_pose, or alternatively return/propagate both a valid and a tracked
boolean so inject_hand_data (which uses is_root_tracked) can add tracked bits
only when the wrist is actually tracked; update references to is_root_tracked
accordingly so last-known-but-untracked poses are not advertised as fully
tracked.
- Around line 116-129: The code currently unconditionally adds
XR_EXT_HAND_TRACKING_EXTENSION_NAME (via including core::HandTracker in
trackers) and XR_MNDX_XDEV_SPACE_EXTENSION_NAME to extensions before
constructing the OpenXR session, which causes xrCreateInstance() to fail if the
runtime lacks those optional extensions; modify the flow to query the runtime's
supported extensions (or probe via core::OpenXRSession/DeviceIOSession helper)
before pushing optional names: only include XR_EXT_HAND_TRACKING_EXTENSION_NAME
if the runtime reports it supported (or defer adding core::HandTracker to
trackers until after support is confirmed), and only push
XR_MNDX_XDEV_SPACE_EXTENSION_NAME if supported; construct m_session =
std::make_shared<core::OpenXRSession>(app_name, extensions) after gating
optional extensions and then call initialize_xdev_hand_trackers()/create hand
trackers as needed so controller fallback remains possible.

In `@src/plugins/manus/install_manus.sh`:
- Around line 53-64: The apt install block in install_manus.sh currently omits a
downloader and unzip and doesn't validate downloads; update the apt-get install
list (the sudo apt-get install -y ... block) to include a downloader (curl or
wget) and unzip, change the SDK fetch command (the curl/wget invocation in the
SDK download/extract step around lines referenced) to use a failing download
mode (curl -fL or wget --server-response -O) so HTTP errors fail, save to a
deterministic filename, then compute and verify the archive checksum (e.g.
sha256sum) against a known expected value before extracting, and only run
unzip/tar after the checksum matches; if verification fails, abort with a clear
error.
- Around line 181-187: The script currently builds only the manus_hand_plugin
target but README expects the manus_hand_tracker_printer binary; update the
build/install steps to include the printer binary: adjust the cmake --build
invocation (or add a second cmake --build call) to also build the
manus_hand_tracker_printer target and ensure the corresponding binary/component
is installed (e.g., include its name alongside manus or call cmake --install for
that component). Locate the build/install lines referencing targets
manus_hand_plugin and component manus and add the manus_hand_tracker_printer
target/component so the documented ./build/bin/manus_hand_tracker_printer exists
after the script runs.
- Around line 173-179: The script currently skips CMake configuration when
build/CMakeCache.txt exists, which leaves stale discovery results after copying
the ManusSDK; change the logic so CMake is forced to reconfigure after the SDK
copy by removing or invalidating build/CMakeCache.txt (or always running the
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release command) instead of conditionally
skipping it; update the block that checks "build/CMakeCache.txt" and ensure the
cmake invocation is executed unconditionally (or after deleting the cache) so
the project is deterministically reconfigured.

In `@src/plugins/manus/install-dependencies.sh`:
- Around line 14-22: The script currently writes "deb
http://deb.debian.org/debian bookworm main" directly into
/etc/apt/sources.list.d/bookworm-gcc.list which can allow unrelated Bookworm
packages to be installed; instead, add an apt pin/priority file that pins only
the specific packages you need (e.g., gcc-11, g++-11, libgcc-11) with a high
priority for the target release, or use an isolated toolchain source (PPA or apt
repository that provides only GCC packages). Update the Debian branch of the
install step (the block that runs apt-get install -y debian-archive-keyring and
echoes the repo) to also create a /etc/apt/preferences.d/bookworm-gcc.pref entry
that pins the listed package names to release "n=bookworm" with a high
Pin-Priority, and ensure apt-get update is called before installing the pinned
packages so only those specific packages are allowed from Bookworm rather than
the whole main archive.
- Around line 38-44: The existing check that skips cloning when the grpc repo
directory exists can leave a stale or dirty checkout; change the else branch to
normalize the existing checkout: fetch all tags and branches, checkout the
pinned tag v1.28.1, hard-reset the worktree to that tag, remove untracked files,
and ensure submodules are synchronized and updated/initialized recursively so
the repo is deterministic before continuing with build steps that expect
v1.28.1.

In `@src/plugins/manus/README.md`:
- Around line 44-46: Update the MANUS version references in the README: change
both URLs and any text that point to 3.1.0 to 3.1.1 (specifically replace
https://docs.manus-meta.com/3.1.0/Resources/ and
https://docs.manus-meta.com/3.1.0/Plugins/SDK/Linux/ with the 3.1.1 equivalents)
so the manual-install instructions match the automated installer; ensure the
mention of the ManusSDK folder and MANUS_SDK_ROOT remains the same but reflects
the 3.1.1 archive name where applicable.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: c7bcbfd3-5e8e-4006-9d8b-2a78c775fabb

📥 Commits

Reviewing files that changed from the base of the PR and between 0e60322 and 8c82616.

📒 Files selected for processing (6)
  • src/plugins/manus/README.md
  • src/plugins/manus/core/manus_hand_tracking_plugin.cpp
  • src/plugins/manus/inc/core/manus_hand_tracking_plugin.hpp
  • src/plugins/manus/install-dependencies.sh
  • src/plugins/manus/install_manus.sh
  • src/plugins/manus/tools/manus_hand_tracker_printer.cpp

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

♻️ Duplicate comments (1)
src/plugins/manus/install_manus.sh (1)

53-64: ⚠️ Potential issue | 🟡 Minor

Install unzip in the minimal dependency path.

The minimal dependency installation doesn't include unzip, but the SDK extraction step (line 113) requires it and will fail with an error if it's not present.

🔧 Proposed fix
         sudo apt-get install -y \
             build-essential \
             cmake \
             git \
             libssl-dev \
             zlib1g-dev \
             libc-ares-dev \
             libzmq3-dev \
             libncurses-dev \
             libudev-dev \
-            libusb-1.0-0-dev
+            libusb-1.0-0-dev \
+            unzip
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/plugins/manus/install_manus.sh` around lines 53 - 64, The minimal
dependency apt-get install block in install_manus.sh is missing unzip, which the
later SDK extraction step requires; update the apt-get install command (the sudo
apt-get install -y ... block) to include unzip alongside the other packages so
the SDK extraction step succeeds without error.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/plugins/manus/core/manus_hand_tracking_plugin.cpp`:
- Around line 471-522: The code currently hardcodes the expected serials "Head
Device (0)" and "Head Device (1)" when matching xdevs (see left_xdev_id,
right_xdev_id and the comparison against properties.serial obtained via
XrGetXDevInfoMNDX); make these strings configurable by reading environment
variables or a config (e.g. MANUS_LEFT_XDEV_SERIAL / MANUS_RIGHT_XDEV_SERIAL)
with fallbacks to the current defaults, use those configured values for the
comparisons instead of the literals, and update the diagnostic message that
prints seen_serials to include the actual expected strings being used so
operators know what was attempted.

In `@src/plugins/manus/install_manus.sh`:
- Line 27: Change the interactive prompt so the shell read invocation that fills
INSTALL_CHOICE uses the -r flag to avoid backslash mangling; in other words,
update the read command (the read that prompts "Enter your choice (1 or 2): "
and sets INSTALL_CHOICE) to include the -r option so input is read raw without
interpreting backslashes.

In `@src/plugins/manus/install-dependencies.sh`:
- Around line 130-139: Replace the multiple echo append lines that write udev
rules into /etc/udev/rules.d/70-manus-hid.rules with a single heredoc to improve
readability and atomicity: in the install-dependencies.sh script, locate the if
block that checks for /etc/udev/rules.d/70-manus-hid.rules and the series of
echo "..." >> /etc/udev/rules.d/70-manus-hid.rules lines, and change them to
create the directory if needed and write the full rules content with a
here-document (e.g., cat <<'EOF' > /etc/udev/rules.d/70-manus-hid.rules ... EOF)
so all rules for SUBSYSTEMS=="usb" and KERNEL=="hidraw*" are written in one
operation.
- Line 54: In the install-dependencies.sh script update the make invocations
that use unquoted command substitution to prevent word splitting: replace
instances of make -j$(nproc) (and the chained commands `make -j$(nproc) && make
-j$(nproc) check && make install && ldconfig`) with versions that quote the
substitution (i.e., use "$(nproc)"); apply the same change to the other
occurrences flagged on lines 85 and 109 so all make -j$(nproc) uses are changed
to make -j"$(nproc)" throughout the script.

In `@src/plugins/manus/README.md`:
- Line 65: Update the README.md markdown formatting: change the ordered list
prefix that begins with "Build from the TeleopCore root:" to use a `1.` prefix
instead of `4.`, add a blank line after all headings (for example after headings
near "Build from the TeleopCore root:" and the later section headings
mentioned), remove the trailing whitespace on the line containing the stray
space (the lone trailing-space line reported), and ensure fenced code blocks
(the blocks around the commands shown later in the README) have a blank line
before and after the ``` fences so they are separated from surrounding text.

---

Duplicate comments:
In `@src/plugins/manus/install_manus.sh`:
- Around line 53-64: The minimal dependency apt-get install block in
install_manus.sh is missing unzip, which the later SDK extraction step requires;
update the apt-get install command (the sudo apt-get install -y ... block) to
include unzip alongside the other packages so the SDK extraction step succeeds
without error.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 7681132b-821c-447c-8bd2-7ca6a732ef5c

📥 Commits

Reviewing files that changed from the base of the PR and between 8c82616 and eccabd6.

📒 Files selected for processing (5)
  • scripts/run_isaac_lab.sh
  • src/plugins/manus/README.md
  • src/plugins/manus/core/manus_hand_tracking_plugin.cpp
  • src/plugins/manus/install-dependencies.sh
  • src/plugins/manus/install_manus.sh

Comment on lines +471 to +522
// Find native hand tracking devices by matching against their serial strings.
//
// NOTE: The serial values "Head Device (0)" (left) and "Head Device (1)" (right) are
// NOT defined by the XR_MNDX_xdev_space specification. They are an observed runtime-
// specific naming convention (e.g. Monado). If a runtime changes these display names
// across firmware or software updates the match below will silently fail.
// See: https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html (XR_MNDX_xdev_space)
XrXDevIdMNDX left_xdev_id = 0;
XrXDevIdMNDX right_xdev_id = 0;
std::vector<std::string> seen_serials;

for (const auto& xdev_id : xdev_ids)
{
XrGetXDevInfoMNDX get_info{ XR_TYPE_GET_XDEV_INFO_MNDX };
get_info.id = xdev_id;

XrXDevPropertiesMNDX properties{ XR_TYPE_XDEV_PROPERTIES_MNDX };
result = m_pfn_get_xdev_properties(m_xdev_list, &get_info, &properties);
if (XR_FAILED(result))
{
continue;
}

std::string serial_str = properties.serial ? properties.serial : "";
seen_serials.push_back(serial_str);

if (serial_str == "Head Device (0)")
{
left_xdev_id = xdev_id;
}
else if (serial_str == "Head Device (1)")
{
right_xdev_id = xdev_id;
}
}

if (left_xdev_id == 0 || right_xdev_id == 0)
{
std::string serials_list;
for (const auto& s : seen_serials)
{
if (!serials_list.empty()) serials_list += ", ";
serials_list += '"';
serials_list += s;
serials_list += '"';
}
std::cerr << "[Manus] Could not match optical hand-tracking XDevs by serial. "
<< "Expected \"Head Device (0)\" (left) and \"Head Device (1)\" (right), "
<< "but found: [" << serials_list << "]. "
<< "These serial strings are runtime-specific and may have changed."
<< std::endl;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider making XDev serial strings configurable.

The hardcoded serial strings "Head Device (0)" and "Head Device (1)" are documented as runtime-specific. While the diagnostic logging is helpful, consider making these configurable via environment variables or a config file for easier adaptation to different runtimes.

This is a forward-looking suggestion—the current implementation with good diagnostics is acceptable for an initial version.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/plugins/manus/core/manus_hand_tracking_plugin.cpp` around lines 471 -
522, The code currently hardcodes the expected serials "Head Device (0)" and
"Head Device (1)" when matching xdevs (see left_xdev_id, right_xdev_id and the
comparison against properties.serial obtained via XrGetXDevInfoMNDX); make these
strings configurable by reading environment variables or a config (e.g.
MANUS_LEFT_XDEV_SERIAL / MANUS_RIGHT_XDEV_SERIAL) with fallbacks to the current
defaults, use those configured values for the comparisons instead of the
literals, and update the diagnostic message that prints seen_serials to include
the actual expected strings being used so operators know what was attempted.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/plugins/manus/install_manus.sh (1)

188-188: 🧹 Nitpick | 🔵 Trivial

Quote $(nproc) to prevent word splitting.

Static analysis flagged unquoted command substitution. While nproc returns a single number, quoting is best practice for defensive scripting.

🔧 Proposed fix
-cmake --build build --target manus_hand_plugin manus_hand_tracker_printer -j$(nproc)
+cmake --build build --target manus_hand_plugin manus_hand_tracker_printer -j"$(nproc)"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/plugins/manus/install_manus.sh` at line 188, The cmake build invocation
uses unquoted command substitution for nproc in the -j flag which can cause word
splitting; update the cmake command in install_manus.sh (the line calling cmake
--build build --target manus_hand_plugin manus_hand_tracker_printer -j$(nproc))
to quote the substitution so the -j argument uses "$(nproc)" to prevent
potential word splitting.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/source/device/manus.rst`:
- Around line 98-104: Update the "Running the Plugin" section to consistently
document CloudXR environment setup by mentioning both options: either source the
provided script (scripts/setup_cloudxr_env.sh) or set the variables manually;
specifically reference the environment variables NV_CXR_RUNTIME_DIR and
XR_RUNTIME_JSON and show the export commands as an alternative, and make the
troubleshooting note (which currently references scripts/setup_cloudxr_env.sh)
match this wording so readers know they can either run the script or export
NV_CXR_RUNTIME_DIR and XR_RUNTIME_JSON themselves.

---

Duplicate comments:
In `@src/plugins/manus/install_manus.sh`:
- Line 188: The cmake build invocation uses unquoted command substitution for
nproc in the -j flag which can cause word splitting; update the cmake command in
install_manus.sh (the line calling cmake --build build --target
manus_hand_plugin manus_hand_tracker_printer -j$(nproc)) to quote the
substitution so the -j argument uses "$(nproc)" to prevent potential word
splitting.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: e1fb9eab-1ae6-4238-8db8-2d4f16a11bdd

📥 Commits

Reviewing files that changed from the base of the PR and between eccabd6 and eca1051.

📒 Files selected for processing (7)
  • docs/source/device/index.rst
  • docs/source/device/manus.rst
  • src/plugins/manus/README.md
  • src/plugins/manus/core/manus_hand_tracking_plugin.cpp
  • src/plugins/manus/inc/core/manus_hand_tracking_plugin.hpp
  • src/plugins/manus/install-dependencies.sh
  • src/plugins/manus/install_manus.sh

Comment on lines +98 to +104
Source the CloudXR environment and start the runtime before running the plugin:

.. code-block:: bash

export NV_CXR_RUNTIME_DIR=~/.cloudxr/run
export XR_RUNTIME_JSON=~/.cloudxr/openxr_cloudxr.json

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Minor inconsistency in CloudXR environment setup references.

The "Running the Plugin" section (lines 98-104) shows manual export commands for CloudXR environment variables, but the troubleshooting section (line 161) references scripts/setup_cloudxr_env.sh. Consider clarifying whether users should source the script or set the variables manually, or document both approaches consistently.

Also applies to: 160-161

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/source/device/manus.rst` around lines 98 - 104, Update the "Running the
Plugin" section to consistently document CloudXR environment setup by mentioning
both options: either source the provided script (scripts/setup_cloudxr_env.sh)
or set the variables manually; specifically reference the environment variables
NV_CXR_RUNTIME_DIR and XR_RUNTIME_JSON and show the export commands as an
alternative, and make the troubleshooting note (which currently references
scripts/setup_cloudxr_env.sh) match this wording so readers know they can either
run the script or export NV_CXR_RUNTIME_DIR and XR_RUNTIME_JSON themselves.

@timvw-manusvr timvw-manusvr force-pushed the manus/hmd-hand-tracking branch from eca1051 to b4c59d3 Compare April 3, 2026 12:26
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 8

Caution

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

⚠️ Outside diff range comments (1)
src/plugins/manus/tools/CMakeLists.txt (1)

23-39: ⚠️ Potential issue | 🟡 Minor

Remove duplicate set_target_properties call.

Lines 23-30 and 32-39 set identical properties on the same target. This appears to be a copy-paste error.

🔧 Proposed fix
 set_target_properties(manus_hand_tracker_printer PROPERTIES
   CXX_VISIBILITY_PRESET hidden
   VISIBILITY_INLINES_HIDDEN YES
   BUILD_WITH_INSTALL_RPATH NO
   SKIP_BUILD_RPATH NO
   BUILD_RPATH "${_ISAAC_MANUS_EFFECTIVE_BUILD_RPATH_STR}"
   RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
 )
-
-set_target_properties(manus_hand_tracker_printer PROPERTIES
-  CXX_VISIBILITY_PRESET hidden
-  VISIBILITY_INLINES_HIDDEN YES
-  BUILD_WITH_INSTALL_RPATH NO
-  SKIP_BUILD_RPATH NO
-  BUILD_RPATH "${_ISAAC_MANUS_EFFECTIVE_BUILD_RPATH_STR}"
-  RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
-)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/plugins/manus/tools/CMakeLists.txt` around lines 23 - 39, The file
contains two identical set_target_properties blocks for the target
manus_hand_tracker_printer; remove the duplicate block so the properties are
only set once. Locate the two set_target_properties(...) invocations that
mention manus_hand_tracker_printer and delete one of them, ensuring the
remaining block retains CXX_VISIBILITY_PRESET, VISIBILITY_INLINES_HIDDEN,
BUILD_WITH_INSTALL_RPATH, SKIP_BUILD_RPATH, BUILD_RPATH and
RUNTIME_OUTPUT_DIRECTORY settings.
♻️ Duplicate comments (3)
src/plugins/manus/install-dependencies.sh (1)

84-84: 🧹 Nitpick | 🔵 Trivial

Quote $(nproc) to follow shell best practices.

Static analysis flagged unquoted command substitution. While unlikely to cause issues in practice, quoting is best practice.

🔧 Proposed fix
-    make -j$(nproc) && make -j$(nproc) check && make install && ldconfig
+    make -j"$(nproc)" && make -j"$(nproc)" check && make install && ldconfig

Also apply to lines 115 and 139:

-    make -j$(nproc)
+    make -j"$(nproc)"
-make -j$(nproc)
+make -j"$(nproc)"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/plugins/manus/install-dependencies.sh` at line 84, The make invocation
uses unquoted command substitution (make -j$(nproc)) which static analysis
flagged; update every occurrence of the job-count invocation (instances of the
literal string "make -j$(nproc)") to quote the substitution as make -j"$(nproc)"
(apply the same change to all occurrences, e.g., the ones around the
build/check/install commands that include ldconfig), ensuring you only change
the quoting around $(nproc) and not other flags or commands.
src/plugins/manus/install_manus.sh (1)

188-188: 🧹 Nitpick | 🔵 Trivial

Quote $(nproc) for consistency.

🔧 Proposed fix
-cmake --build build --target manus_hand_plugin manus_hand_tracker_printer -j$(nproc)
+cmake --build build --target manus_hand_plugin manus_hand_tracker_printer -j"$(nproc)"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/plugins/manus/install_manus.sh` at line 188, The cmake build invocation
uses an unquoted command substitution for the parallel jobs flag; update the
cmake command that builds the manus targets (the line invoking cmake --build
with targets manus_hand_plugin and manus_hand_tracker_printer) to quote the
$(nproc) substitution (e.g. use -j"$(nproc)" or -j "$(nproc)") so the shell
treats the expansion consistently and safely.
docs/source/device/manus.rst (1)

100-105: ⚠️ Potential issue | 🟡 Minor

Document the CloudXR setup path consistently.

Lines 100-105 only show manual exports, while Lines 167-168 tell readers to source scripts/setup_cloudxr_env.sh. Either document both options in both places or standardize on one flow; right now the troubleshooting note contradicts the main run instructions.

Also applies to: 167-168

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/source/device/manus.rst` around lines 100 - 105, The docs currently show
manual export commands (NV_CXR_RUNTIME_DIR and XR_RUNTIME_JSON) in one place and
instruct readers to source scripts/setup_cloudxr_env.sh elsewhere; make these
consistent by choosing one canonical setup flow and updating both locations to
match: either replace the manual export block with a note telling users to
source scripts/setup_cloudxr_env.sh (and mention that the script sets
NV_CXR_RUNTIME_DIR and XR_RUNTIME_JSON), or insert the explicit export commands
into the later troubleshooting section; update any text that references “source
the CloudXR environment” to use the same phrasing (e.g., “source
scripts/setup_cloudxr_env.sh” or “export NV_CXR_RUNTIME_DIR and
XR_RUNTIME_JSON”) so both the main run instructions and the troubleshooting note
are identical.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/source/device/manus.rst`:
- Around line 138-140: Update the sentence to match the implementation: state
that when XR_MNDX_xdev_space is supported the plugin prefers the XDev wrist pose
and only falls back to the controller pose if XDev returns no valid wrist pose;
clarify that if XDev returns a valid-but-untracked wrist pose the plugin keeps
that pose but clears the tracked bits rather than falling back. Reference
XR_MNDX_xdev_space and the logic in manus_hand_tracking_plugin.cpp that
distinguishes "no valid wrist pose" from "valid-but-untracked" so the docs
reflect the actual behavior.

In `@src/plugins/manus/core/manus_hand_tracking_plugin.cpp`:
- Around line 415-423: The cached node topology (tracker.m_left_node_info and
tracker.m_right_node_info) isn’t cleared when CoreSdk_GetRawSkeletonNodeCount
fails or returns 0, leaving stale topology on reconnect; update the connect
handling in manus_hand_tracking_plugin.cpp around the
CoreSdk_GetRawSkeletonNodeCount calls so you explicitly clear
tracker.m_left_node_info (and symmetrically tracker.m_right_node_info in the
other block) before attempting to repopulate, and also clear them on any
non-success return from CoreSdk_GetRawSkeletonNodeInfoArray; use the existing
mutex (tracker.m_skeleton_mutex) while clearing/resizing to avoid races and
mirror this change in the other occurrence referenced (the block at lines
429-436).

In `@src/plugins/manus/README.md`:
- Line 76: Fix the Markdown formatting in README.md by ensuring each heading
(e.g., "Setup CloudXR Environment" and the other headings referenced around the
sections for lines ~86, ~95, and ~102-106) is followed by a blank line, and
remove the trailing space at the end of the line currently at line 106; update
the headings and the paragraph breaks so all top-level and sub-headings have a
single blank line after them and trim any trailing whitespace on the affected
lines.
- Around line 117-122: The fenced code block in README.md lacks blank lines
before and after which violates Markdown lint; edit the Manus README (around the
USB permission instructions) to ensure there is an empty line before the opening
```bash and an empty line after the closing ``` so the block is separated from
surrounding text and the commands ("sudo udevadm control --reload-rules" / "sudo
udevadm trigger") are on their own fenced block lines.

In `@src/plugins/manus/tools/CMakeLists.txt`:
- Around line 4-5: CMake now marks Vulkan and X11 as REQUIRED via
find_package(Vulkan REQUIRED) and find_package(X11 REQUIRED), but the installer
scripts don't install the corresponding dev packages; update the package lists
in install_manus.sh and install-dependencies.sh to include libvulkan-dev and
libx11-dev (and any distro-specific aliases if your script supports multiple
distros) so CMake can find those libraries during configure; ensure you add them
to the same apt/yum/dnf install lines used for other dev libs and update any
package-check or dependency arrays the scripts use.

In `@src/plugins/manus/tools/manus_hand_tracker_printer.cpp`:
- Around line 28-40: The detached vis_thread captures tracker by reference which
risks accessing a destroyed singleton; replace the detached std::thread with a
std::jthread (or a joinable std::thread plus a shutdown signal) and ensure the
visualizer gets a safe owning or lifetime-managed handle (e.g., pass a
std::shared_ptr to tracker or copy any needed state) instead of a raw reference;
also update plugins::manus::HandVisualizer::run to accept a std::stop_token (or
a custom shutdown flag) and periodically check it so the jthread can request
shutdown cleanly before destruction.

In `@src/plugins/manus/tools/manus_hand_visualizer.hpp`:
- Around line 271-289: The HandVisualizer() constructor can throw after creating
native resources (initXlib(), initVulkan(), createSwapchain(),
createRenderPass(), createPipeline(), createFramebuffers(),
createCommandBuffers(), createSyncObjects(), createVertexBuffer()) and so the
destructor won't run; add a dedicated cleanup helper (e.g.,
cleanupPartialResources() or teardownResources()) that releases X11/Vulkan
handles created so far and call it from the catch block before rethrowing, or
better yet replace the raw handles with RAII wrapper members so partial
construction is safely undone automatically; keep the destructor for full
cleanup but ensure the catch path explicitly invokes the shared teardown helper
or relies on RAII members to avoid leaks.
- Around line 988-1002: Move the vkResetFences(m_dev, 1, &m_fence_in_flight)
call so it happens only after a successful vkAcquireNextImageKHR() (i.e., after
acquiring img_idx), not before acquisition, to avoid leaving the fence
unsignaled when vkAcquireNextImageKHR() returns VK_ERROR_OUT_OF_DATE_KHR; also,
after the swapchain recreation paths that call destroySwapchainResources(),
createSwapchain(), and createFramebuffers() (both in the vkAcquireNextImageKHR()
error branch and in the vkQueuePresentKHR() error branch), call
createCommandBuffers() to rebuild m_cmd_bufs to match the new m_sc_images size
so subsequent accesses like m_cmd_bufs[img_idx] cannot go out-of-bounds.

---

Outside diff comments:
In `@src/plugins/manus/tools/CMakeLists.txt`:
- Around line 23-39: The file contains two identical set_target_properties
blocks for the target manus_hand_tracker_printer; remove the duplicate block so
the properties are only set once. Locate the two set_target_properties(...)
invocations that mention manus_hand_tracker_printer and delete one of them,
ensuring the remaining block retains CXX_VISIBILITY_PRESET,
VISIBILITY_INLINES_HIDDEN, BUILD_WITH_INSTALL_RPATH, SKIP_BUILD_RPATH,
BUILD_RPATH and RUNTIME_OUTPUT_DIRECTORY settings.

---

Duplicate comments:
In `@docs/source/device/manus.rst`:
- Around line 100-105: The docs currently show manual export commands
(NV_CXR_RUNTIME_DIR and XR_RUNTIME_JSON) in one place and instruct readers to
source scripts/setup_cloudxr_env.sh elsewhere; make these consistent by choosing
one canonical setup flow and updating both locations to match: either replace
the manual export block with a note telling users to source
scripts/setup_cloudxr_env.sh (and mention that the script sets
NV_CXR_RUNTIME_DIR and XR_RUNTIME_JSON), or insert the explicit export commands
into the later troubleshooting section; update any text that references “source
the CloudXR environment” to use the same phrasing (e.g., “source
scripts/setup_cloudxr_env.sh” or “export NV_CXR_RUNTIME_DIR and
XR_RUNTIME_JSON”) so both the main run instructions and the troubleshooting note
are identical.

In `@src/plugins/manus/install_manus.sh`:
- Line 188: The cmake build invocation uses an unquoted command substitution for
the parallel jobs flag; update the cmake command that builds the manus targets
(the line invoking cmake --build with targets manus_hand_plugin and
manus_hand_tracker_printer) to quote the $(nproc) substitution (e.g. use
-j"$(nproc)" or -j "$(nproc)") so the shell treats the expansion consistently
and safely.

In `@src/plugins/manus/install-dependencies.sh`:
- Line 84: The make invocation uses unquoted command substitution (make
-j$(nproc)) which static analysis flagged; update every occurrence of the
job-count invocation (instances of the literal string "make -j$(nproc)") to
quote the substitution as make -j"$(nproc)" (apply the same change to all
occurrences, e.g., the ones around the build/check/install commands that include
ldconfig), ensuring you only change the quoting around $(nproc) and not other
flags or commands.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: c80c078e-0ac4-489c-a944-6254a5229aeb

📥 Commits

Reviewing files that changed from the base of the PR and between eca1051 and b4c59d3.

📒 Files selected for processing (11)
  • docs/source/device/index.rst
  • docs/source/device/manus.rst
  • scripts/run_isaac_lab.sh
  • src/plugins/manus/README.md
  • src/plugins/manus/core/manus_hand_tracking_plugin.cpp
  • src/plugins/manus/inc/core/manus_hand_tracking_plugin.hpp
  • src/plugins/manus/install-dependencies.sh
  • src/plugins/manus/install_manus.sh
  • src/plugins/manus/tools/CMakeLists.txt
  • src/plugins/manus/tools/manus_hand_tracker_printer.cpp
  • src/plugins/manus/tools/manus_hand_visualizer.hpp

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

♻️ Duplicate comments (1)
docs/source/device/manus.rst (1)

136-138: ⚠️ Potential issue | 🟡 Minor

Recheck the XDev fallback wording.

This sentence says controller fallback happens whenever the optical wrist is not actively tracked. If src/plugins/manus/core/manus_hand_tracking_plugin.cpp still falls back only when XDev fails to return a valid wrist pose, this wording is too strict and will mislead troubleshooting. If the branch is keyed off XR_SPACE_LOCATION_POSITION_VALID_BIT rather than XR_SPACE_LOCATION_POSITION_TRACKED_BIT, please document that exact condition here.

#!/bin/bash
# Inspect the wrist-pose selection logic used by the Manus plugin.
rg -n -C5 'inject_hand_data|get_controller_wrist_pose|XR_SPACE_LOCATION_POSITION_VALID_BIT|XR_SPACE_LOCATION_POSITION_TRACKED_BIT|m_xdev_available' src/plugins/manus/core/manus_hand_tracking_plugin.cpp
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/source/device/manus.rst` around lines 136 - 138, Confirm the actual
wrist-pose selection logic in manus_hand_tracking_plugin.cpp (check functions
inject_hand_data, get_controller_wrist_pose and the m_xdev_available flag) and
update the docs text to state the precise fallback condition: whether the plugin
falls back to controller pose when XR_MNDX_xdev_space is unavailable
(m_xdev_available==false) or when the runtime returns a wrist pose lacking
XR_SPACE_LOCATION_POSITION_VALID_BIT versus
XR_SPACE_LOCATION_POSITION_TRACKED_BIT; change the sentence to explicitly name
which bit is checked (POSITION_VALID_BIT or POSITION_TRACKED_BIT) and/or that
the fallback occurs only when m_xdev_available is false, matching the code
exactly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/plugins/manus/70-manus-hid.rules`:
- Around line 2-5: The udev rules currently use MODE:="0666" which makes matched
USB and hidraw devices world-writable; update the rules matching
SUBSYSTEMS=="usb" with ATTRS{idVendor}=="3325" and ATTRS{idVendor}=="1915",
ATTRS{idProduct}=="83fd" and the KERNEL=="hidraw*" rule to remove MODE:="0666"
and instead assign a group and restrictive mode (for example set MODE:="0660"
and GROUP:="plugdev" or GROUP:="manus"), and optionally add TAG+="uaccess" if
you want the active logged-in user to get access; ensure all three rule lines
use the same GROUP and MODE change so devices are not world-writable.

In `@src/plugins/manus/install_manus.sh`:
- Around line 41-46: The script only installs
/etc/udev/rules.d/70-manus-hid.rules when the file is missing; change it to
detect and refresh the installed rules when the bundled file at
"$SCRIPT_DIR/70-manus-hid.rules" differs (or is newer) so updates self-repair
USB access; implement this by comparing the source and destination (e.g., using
cmp -s or checksums) and if they differ, copy the new file with sudo (preserving
mode/ownership as needed) and run sudo udevadm control --reload-rules (and
optionally sudo udevadm trigger) to apply the change, referencing the existing
variables and commands (SCRIPT_DIR, 70-manus-hid.rules, udevadm control
--reload-rules).
- Around line 145-147: The install script uses "cmake --install build
--component manus" but none of the Manus CMake install rules declare COMPONENT
manus (targets: manus_hand_plugin, manus_plugin_core, SDK library in
src/plugins/manus/CMakeLists.txt and plugin files in
src/plugins/manus/app/CMakeLists.txt) and the built tool
manus_hand_tracker_printer has no install rule; fix by either removing the
--component manus filter from install_manus.sh or by adding COMPONENT manus to
all relevant install(...) calls and adding an install(...) rule for
manus_hand_tracker_printer in src/plugins/manus/tools/CMakeLists.txt so the
cmake install command actually installs the expected artifacts.

In `@src/plugins/manus/README.md`:
- Around line 66-70: The manual build instructions only build the
manus_hand_plugin target but later verification expects the
manus_hand_tracker_printer binary; update the commands to also build (and
install if needed) the printer target by running cmake --build build --target
manus_hand_tracker_printer -j (or build both targets or the appropriate
component during cmake --install) so that manus_hand_tracker_printer exists for
the verification step; update the README steps that currently reference
manus_hand_plugin to include manus_hand_tracker_printer.

---

Duplicate comments:
In `@docs/source/device/manus.rst`:
- Around line 136-138: Confirm the actual wrist-pose selection logic in
manus_hand_tracking_plugin.cpp (check functions inject_hand_data,
get_controller_wrist_pose and the m_xdev_available flag) and update the docs
text to state the precise fallback condition: whether the plugin falls back to
controller pose when XR_MNDX_xdev_space is unavailable (m_xdev_available==false)
or when the runtime returns a wrist pose lacking
XR_SPACE_LOCATION_POSITION_VALID_BIT versus
XR_SPACE_LOCATION_POSITION_TRACKED_BIT; change the sentence to explicitly name
which bit is checked (POSITION_VALID_BIT or POSITION_TRACKED_BIT) and/or that
the fallback occurs only when m_xdev_available is false, matching the code
exactly.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: edb58f2b-32ce-479e-a621-732ba2e1afaa

📥 Commits

Reviewing files that changed from the base of the PR and between b4c59d3 and a37bfd0.

📒 Files selected for processing (4)
  • docs/source/device/manus.rst
  • src/plugins/manus/70-manus-hid.rules
  • src/plugins/manus/README.md
  • src/plugins/manus/install_manus.sh

Comment on lines +2 to +5
SUBSYSTEMS=="usb", ATTRS{idVendor}=="3325", MODE:="0666"
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1915", ATTRS{idProduct}=="83fd", MODE:="0666"
# HIDAPI/hidraw
KERNEL=="hidraw*", ATTRS{idVendor}=="3325", MODE:="0666"
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

Avoid world-writable udev rules.

MODE:="0666" grants every local user raw read/write access to the matched USB and hidraw devices. Because install_manus.sh installs this file into /etc/udev/rules.d, that becomes the host-wide default. Please scope access to the active user or a dedicated group instead of making the devices universally writable.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/plugins/manus/70-manus-hid.rules` around lines 2 - 5, The udev rules
currently use MODE:="0666" which makes matched USB and hidraw devices
world-writable; update the rules matching SUBSYSTEMS=="usb" with
ATTRS{idVendor}=="3325" and ATTRS{idVendor}=="1915", ATTRS{idProduct}=="83fd"
and the KERNEL=="hidraw*" rule to remove MODE:="0666" and instead assign a group
and restrictive mode (for example set MODE:="0660" and GROUP:="plugdev" or
GROUP:="manus"), and optionally add TAG+="uaccess" if you want the active
logged-in user to get access; ensure all three rule lines use the same GROUP and
MODE change so devices are not world-writable.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: WIP

Development

Successfully merging this pull request may close these issues.

4 participants