openclaw - ✅(Solved) Fix Remote macOS skill eligibility ignores system.which bins object response, so apple-notes stays missing memo [1 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#71877Fetched 2026-04-26 05:07:10
View on GitHub
Comments
1
Participants
2
Timeline
3
Reactions
0
Timeline (top)
closed ×1commented ×1cross-referenced ×1

On a Linux/container Gateway with a connected macOS node, remote macOS skill eligibility still reports apple-notes as missing memo even though the Mac node successfully exposes memo via system.which.

The issue appears to be that the remote bin probe parser only accepts bins as an array or stdout as a string, while system.which returns bins as an object map of { binName: resolvedPath }.

Root Cause

apple-notes should be eligible because:

PR fix notes

PR #71894: fix(skills): parse object-map remote bin probes

Description (problem / solution / changelog)

Summary

  • Problem: remote node bin refresh parsed bins only when it was an array, but the JS node-host system.which path returns bins as an object map of bin name to resolved path.
  • Why it matters: Docker/Linux gateway setups with a remote macOS node can keep macOS-only skills such as apple-notes marked missing even when the remote node resolved memo successfully.
  • What changed: parseBinProbePayload() now accepts object-map bins responses and records the object keys as available bins.
  • What did NOT change (scope boundary): local bin detection, system.run stdout parsing, array-shaped bins parsing, and remote command selection are unchanged.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #71877
  • Related #28406
  • This PR fixes a bug or regression

Root Cause (if applicable)

  • Root cause: parseBinProbePayload() handled array-shaped bins and stdout, but not Record<string, string> responses from system.which.
  • Missing detection / guardrail: existing remote skills tests did not cover a successful system.which object-map response through refreshRemoteNodeBins().
  • Contributing context (if known): #28406 previously fixed the same parser gap but was closed by the stale bot rather than merged.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/infra/skills-remote.test.ts
  • Scenario the test should lock in: refreshRemoteNodeBins() receives payloadJSON: { bins: { memo: /opt/homebrew/bin/memo } } from system.which and makes memo available to remote skill eligibility.
  • Why this is the smallest reliable guardrail: it exercises the public refresh path used by remote nodes without requiring a live paired macOS node.
  • Existing test that already covers this (if any): none for object-map bins success responses.
  • If no new test is added, why not: N/A, regression test added.

User-visible / Behavior Changes

Remote macOS skill eligibility can now recognize bins reported by object-map system.which responses, so skills such as apple-notes can become eligible when a connected macOS node resolves memo.

Diagram (if applicable)

Before:
system.which -> { bins: { memo: /opt/homebrew/bin/memo } } -> [] -> apple-notes still missing memo

After:
system.which -> { bins: { memo: /opt/homebrew/bin/memo } } -> [memo] -> apple-notes can satisfy memo remotely

Security Impact (required)

  • New permissions/capabilities? (No)
  • Secrets/tokens handling changed? (No)
  • New/changed network calls? (No)
  • Command/tool execution surface changed? (No)
  • Data access scope changed? (No)
  • If any Yes, explain risk + mitigation: N/A

Repro + Verification

Environment

  • OS: Windows local dev for tests; reported user path is Linux/Docker gateway plus remote macOS node
  • Runtime/container: local pnpm/vitest
  • Model/provider: N/A
  • Integration/channel (if any): bundled skills remote node eligibility
  • Relevant config (redacted): test workspace skill requiring one darwin bin

Steps

  1. Register a remote darwin node with system.run and system.which support.
  2. Refresh remote bins for a workspace skill requiring memo.
  3. Return payloadJSON from the node probe as { bins: { memo: /opt/homebrew/bin/memo } }.

Expected

  • memo is recorded as available and remote skill eligibility reports hasBin(memo) true.

Actual

  • Before this fix, object-map bins responses fell through to [], leaving the skill missing its remote bin.

Evidence

  • Passing regression coverage: pnpm exec vitest run src/infra/skills-remote.test.ts -> 1 file passed, 10 tests passed
  • Changed-file gate: pnpm check:changed passed
  • Whitespace check: git diff --check passed

Human Verification (required)

  • Verified scenarios: object-map system.which response through refreshRemoteNodeBins(); target remote skills test suite.
  • Edge cases checked: existing tests still cover stale bin clearing, disconnected nodes, cached metadata, coalesced probes, non-mac nodes, and note suppression.
  • What you did not verify: live Docker gateway + remote macOS node E2E, because that requires a paired remote Mac environment.

Review Conversations

N/A, no review conversations on this PR yet.

Compatibility / Migration

  • Backward compatible? (Yes)
  • Config/env changes? (No)
  • Migration needed? (No)
  • If yes, exact upgrade steps: N/A

Risks and Mitigations

  • Risk: unexpected object-shaped bins payloads could now expose object keys as bin names.
    • Mitigation: this branch only runs after the existing array check, trims/filters names, and matches the JS node-host system.which response shape that only includes found binaries.

Changed files

  • src/infra/skills-remote.test.ts (modified, +61/-0)
  • src/infra/skills-remote.ts (modified, +5/-0)

Code Example

{
  "ok": true,
  "command": "system.which",
  "payload": {
    "bins": {
      "memo": "/opt/homebrew/bin/memo"
    }
  },
  "payloadJSON": "{\"bins\":{\"memo\":\"/opt/homebrew/bin/memo\"}}"
}

---

memo, version 0.5.2
memo notes --help works

---

{
  "name": "apple-notes",
  "missing": {
    "bins": ["memo"],
    "os": ["darwin"]
  }
}

---

Array.isArray(parsed.bins)
typeof parsed.stdout === "string"

---

parsed.bins = { memo: "/opt/homebrew/bin/memo" }

---

if (parsed.bins && typeof parsed.bins === "object" && !Array.isArray(parsed.bins)) {
  return Object.keys(parsed.bins)
    .map((bin) => normalizeOptionalString(String(bin)) ?? "")
    .filter(Boolean);
}
RAW_BUFFERClick to expand / collapse

Summary

On a Linux/container Gateway with a connected macOS node, remote macOS skill eligibility still reports apple-notes as missing memo even though the Mac node successfully exposes memo via system.which.

The issue appears to be that the remote bin probe parser only accepts bins as an array or stdout as a string, while system.which returns bins as an object map of { binName: resolvedPath }.

Environment

  • OpenClaw: 2026.4.23
  • Gateway host: Linux / containerized OpenClaw on Unraid
  • Connected node: macOS / darwin node named Mac
  • Node capabilities include:
    • system.run
    • system.run.prepare
    • system.which
  • Affected bundled skill: apple-notes
  • Required binary: memo

Reproduction / observed behavior

  1. Enable bundled apple-notes via skills.allowBundled.
  2. Pair/connect a macOS node with system.which and system.run available.
  3. Install memo on the Mac node.
  4. Confirm the node can resolve memo:
{
  "ok": true,
  "command": "system.which",
  "payload": {
    "bins": {
      "memo": "/opt/homebrew/bin/memo"
    }
  },
  "payloadJSON": "{\"bins\":{\"memo\":\"/opt/homebrew/bin/memo\"}}"
}
  1. Confirm memo itself runs on the Mac node:
memo, version 0.5.2
memo notes --help works
  1. Run openclaw skills check --json.

Actual result:

{
  "name": "apple-notes",
  "missing": {
    "bins": ["memo"],
    "os": ["darwin"]
  }
}

Expected result:

apple-notes should be eligible because:

  • a connected remote macOS node is available
  • that node supports system.run
  • system.which successfully resolved memo

Suspected root cause

In the built output I inspected, parseBinProbePayload() handles:

Array.isArray(parsed.bins)
typeof parsed.stdout === "string"

but does not handle the system.which response shape:

parsed.bins = { memo: "/opt/homebrew/bin/memo" }

So a successful system.which response is parsed as an empty bin list, and remote skill eligibility never sees memo.

There was a closed, unmerged PR that appears to address this exact parser gap:

Suggested fix

Handle object/map-shaped bins responses in parseBinProbePayload(), for example:

if (parsed.bins && typeof parsed.bins === "object" && !Array.isArray(parsed.bins)) {
  return Object.keys(parsed.bins)
    .map((bin) => normalizeOptionalString(String(bin)) ?? "")
    .filter(Boolean);
}

Impact

Docker/Linux Gateway + remote macOS node setups cannot use macOS-only skills like apple-notes even when the node and required binary are correctly configured. The skill remains hidden/missing from eligibility because the successful remote probe is misparsed.

extent analysis

TL;DR

Update the parseBinProbePayload() function to handle object-shaped bins responses from system.which to correctly parse the memo binary path.

Guidance

  • Review the parseBinProbePayload() function to ensure it can handle both array and object-shaped bins responses.
  • Verify that the system.which response is correctly parsed by checking the bins property in the response payload.
  • Consider applying the suggested fix from the closed PR (https://github.com/openclaw/openclaw/pull/28406) to handle object-shaped bins responses.
  • Test the updated parseBinProbePayload() function with the provided example response to ensure it correctly extracts the memo binary path.

Example

if (parsed.bins && typeof parsed.bins === "object" && !Array.isArray(parsed.bins)) {
  return Object.keys(parsed.bins)
    .map((bin) => normalizeOptionalString(String(bin)) ?? "")
    .filter(Boolean);
}

Notes

The suggested fix assumes that the parseBinProbePayload() function is the root cause of the issue. However, further testing and verification may be necessary to confirm this.

Recommendation

Apply the workaround by updating the parseBinProbePayload() function to handle object-shaped bins responses, as this will allow the apple-notes skill to be correctly eligible on remote macOS nodes with the required memo binary.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING