[GH-ISSUE #1711] [Bug] client-only skill setup reports a missing shared skill #571

Closed
opened 2026-10-15 18:26:18 +00:00 by bsakaguchi · 2 comments
Owner

Originally created by @coygeek on GitHub (Oct 11, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/1711

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Setup, packaging, or upgrade

Observed behavior

setup --skill-client claude_code --yes --json installs the correct Claude Code skill bundle but returns needs_human, exits 1 and reports the skill as missing. Its final readiness check inspects the shared destination rather than the independently selected client skill destination. The same false failure persists on a no-change rerun, while a client-scoped doctor immediately confirms the installed skill and registration are healthy.

On each tested artifact, the registration control returned ready, exit 0. The selected Claude skill setup returned appliedActions: ["installed_skill"] and installed all seven files byte for byte, but reported this final state:

{"status":"needs_human","doctor":{"healthy":false,"scope":{"mode":"explicit","clients":[],"providers":[],"skill":true,"target":null},"identity":{"skill":{"state":"missing"}}},"remediation":"Hopper is optional for non-Hopper providers. Rerun with --yes --install-hopper for deep native analysis."}

Without changing files, doctor --client claude_code --skill --json returned exit 0, healthy: true and identity.skill.state: "aligned". Repeating the affected setup returned exit 1 and needs_human with no planned or applied actions. The shared-destination control returned exit 0 and ready. Thus two affected invocations out of two failed per tested artifact, while all controls succeeded. The source probe reproduced the same results after rebuilding the updated main entrypoint. The release sequence also reproduced the same results on a fresh-home rerun after adding an isolated working directory and clearing profile overrides.

Reproduction

Use a disposable home that contains an aligned Claude Code MCP registration and no shared REA skill. The following executed script creates that state itself, compares all seven installed skill files with the packaged bundle, checks the selected client explicitly, repeats the affected command, and then tests the shared-destination control. Save it as reproduce-skill-setup.mjs outside the checkout and run node reproduce-skill-setup.mjs /absolute/path/to/built/rea. It removes the trial home after collecting results. The same script accepts the package root of a separately installed published release.

import {mkdtempSync, existsSync, readFileSync, rmSync} from 'node:fs';
import {join,dirname} from 'node:path';
import {spawnSync} from 'node:child_process';
const root=process.argv[2];
if (!root) throw new Error('Pass the absolute path to a built REA checkout or extracted package');
const home=mkdtempSync('/tmp/agent-work.');
const env={...process.env,HOME:home,PATH:dirname(process.execPath)+':'+process.env.PATH};
for(const key of ['CLAUDE_CONFIG_DIR','CODEX_HOME','COPILOT_HOME','OPENCODE_CONFIG','OPENCODE_CONFIG_DIR','XDG_CONFIG_HOME','GEMINI_CLI_HOME','GEMINI_CLI_SYSTEM_SETTINGS_PATH','GEMINI_CLI_SYSTEM_DEFAULTS_PATH','GEMINI_CLI_TRUSTED_FOLDERS_PATH','QWEN_HOME','GROK_HOME','PI_CODING_AGENT_DIR','PI_CONFIG_DIR','HERMES_HOME','SAND_DATA_ROOT','APPDATA','OMP_PROFILE','PI_PROFILE']) delete env[key];
const cli=root+'/scripts/rea.mjs';
const run=(args)=>{const r=spawnSync(process.execPath,[cli,...args],{env,cwd:home,encoding:'utf8',timeout:40000});let v;try{v=JSON.parse(r.stdout)}catch{};return {args,exit:r.status,error:r.error?.message,stdout:v??r.stdout,stderr:r.stderr}};
const project=(result)=>({args:result.args,exit:result.exit,status:result.stdout.status,plannedActions:result.stdout.plannedActions?.map(a=>({id:a.id,kind:a.kind})),appliedActions:result.stdout.appliedActions,scope:result.stdout.doctor?.scope??result.stdout.scope,skill:result.stdout.doctor?.identity?.skill??result.stdout.identity?.skill,healthy:result.stdout.doctor?.healthy??result.stdout.healthy,scopeChecks:result.stdout.scope_checks?.map(({name,ok,classification})=>({name,ok,classification})),remediation:result.stdout.remediation});
try {
const registration=run(['setup','--client','claude_code','--skill=false','--yes','--json']);
const setup=run(['setup','--skill-client','claude_code','--yes','--json']);
const files=['SKILL.md','references/connection-and-recovery.md','references/native-and-artifacts.md','references/javascript-applications.md','references/android-applications.md','references/runtime-observation.md','references/evidence-workflows.md'];
const byteAlignment=files.map(path=>({path,matches:readFileSync(join(home,'.claude/skills/reverse-engineer-anything',path)).equals(readFileSync(join(root,'skills/reverse-engineer-anything',path)))}));
const result={node:process.version,registration:project(registration),setup:project(setup),byteAlignment,claudeSkillExists:existsSync(join(home,'.claude/skills/reverse-engineer-anything/SKILL.md')),sharedSkillExists:existsSync(join(home,'.agents/skills/reverse-engineer-anything/SKILL.md')),doctorClaude:project(run(['doctor','--client','claude_code','--skill','--json'])),rerun:project(run(['setup','--skill-client','claude_code','--yes','--json'])),controlShared:project(run(['setup','--skill-client','shared','--yes','--json']))};
console.log(JSON.stringify(result,null,2));
} finally {
rmSync(home,{recursive:true,force:true});
}

The relevant CLI sequence inside that isolated environment is:

rea setup --client claude_code --skill=false --yes --json
rea setup --skill-client claude_code --yes --json
rea doctor --client claude_code --skill --json
rea setup --skill-client claude_code --yes --json
rea setup --skill-client shared --yes --json

Expected behavior

Skill-only setup should verify the client skill copy selected by --skill-client, report its aligned identity, return ready and exit 0 after a successful installation or no-change rerun. A missing unselected shared copy and the absence of optional Hopper should not make that selected scope fail. The command should keep registration selection independent from skill destination selection.

Impact and scope

A supported client-only skill refresh reports failure after successful installation, including on a no-change rerun. This disrupts setup and maintenance automation while the installed client skill remains usable. The verified workaround is to check readiness with the explicit client-scoped doctor command. Provider execution and native client skill discovery were not exercised.

REA version

The isolated CLI sequence ran on current main at revision 693ed332b58d05192f55b8192d2c0c4bc4f4824a, package version 6.4.0, and on a separately installed published npm rea-agents@6.4.0 artifact.

Runtime and platform

Both ran on macOS 27.0 arm64 with Node.js v26.10.0, which the package's runtime engine range accepts. The source checkout used locked dependencies installed with npm ci --ignore-scripts and a successful npm run build:cached; the release used a clean npm install --ignore-scripts dependency installation. Each CLI sequence used a fresh temporary home and working directory with client-directory overrides removed and the direct Node executable directory first on PATH. No client login, target binary or analysis engine was required.

Target and artifact context

No target artifact is required; this is a standalone client skill setup and readiness sequence.

Interface

Package or setup

Earliest failure stage

Setup or provider admission

Relevant output or evidence

  • Expected source: src/cli/setupCommands.ts:65-69 defines independent client skill destination selection; docs/installation.md:329-338,365-367 describes selected skill copies, identity readiness and setup's final checks. src/application/UpdateMaintenance.ts:114-120 also emits the affected independent skill-refresh command.
  • Failure source: The inline production CLI probe records successful byte-aligned installation followed by false missing identity and a no-change failure. src/application/Setup.ts:128,314-326,516-528 retains the chosen skill destination for writing but leaves it out of the final readiness clients; src/application/Doctor.ts:204-209 uses those clients for skill identity, and src/application/SupportedClients.ts:614-615 maps an empty selection to the shared root.
  • Evidence provenance: observed
  • Local verification: reproduced
  • Reproduction completeness: complete

Evidence provenance details: observed production CLI behavior in isolated temporary homes on the source build and separately installed release; source tracing explains the mismatched final check.

Local verification details: reproduced on both tested artifacts, with registration, selected-doctor, file-alignment and shared-destination controls.

Reproduction completeness details: complete for the standalone client-only refresh sequence above.

Pinned source breadcrumbs: skill selection and final setup check, doctor selection, and maintenance refresh command.

This differs from a wrong install destination or an omitted skill bundle: the chosen client receives the complete correct files. The independent final readiness result is the failed contract.

Typed outcome or recovery expected

The client-only install and no-change rerun should return ready, exit 0 and an aligned selected skill identity.

Additional context

Repeat the isolated registered-client sequence with no shared skill present. Require client-only skill setup and its no-change rerun to return ready, exit 0 and an aligned selected skill identity; require all seven files to remain byte-aligned with the package. Keep the explicit client-scoped doctor and shared-destination controls passing. Also verify that a genuinely missing or damaged selected client skill still produces a meaningful failure, and that restoration does not silently add an unselected shared copy or change unrelated registrations.

Triage assessment

  • Impact level: P2
  • Assessment status: supported
  • Impact basis: A supported client-only skill refresh reports failure and unrelated Hopper remediation after successful installation, including on repeated no-change runs. This disrupts setup/maintenance automation while the installed client skill itself remains usable.
  • Workaround status: available
  • Workaround basis: With the existing aligned registration, the executed doctor --client claude_code --skill --json command returned exit 0 and verified the installed selected skill without changing files. Users can use that result to check readiness after the false setup failure; it does not correct setup's own exit status.
Originally created by @coygeek on GitHub (Oct 11, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/1711 ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Setup, packaging, or upgrade ### Observed behavior `setup --skill-client claude_code --yes --json` installs the correct Claude Code skill bundle but returns `needs_human`, exits 1 and reports the skill as missing. Its final readiness check inspects the shared destination rather than the independently selected client skill destination. The same false failure persists on a no-change rerun, while a client-scoped doctor immediately confirms the installed skill and registration are healthy. On each tested artifact, the registration control returned `ready`, exit 0. The selected Claude skill setup returned `appliedActions: ["installed_skill"]` and installed all seven files byte for byte, but reported this final state: ```json {"status":"needs_human","doctor":{"healthy":false,"scope":{"mode":"explicit","clients":[],"providers":[],"skill":true,"target":null},"identity":{"skill":{"state":"missing"}}},"remediation":"Hopper is optional for non-Hopper providers. Rerun with --yes --install-hopper for deep native analysis."} ``` Without changing files, `doctor --client claude_code --skill --json` returned exit 0, `healthy: true` and `identity.skill.state: "aligned"`. Repeating the affected setup returned exit 1 and `needs_human` with no planned or applied actions. The shared-destination control returned exit 0 and `ready`. Thus two affected invocations out of two failed per tested artifact, while all controls succeeded. The source probe reproduced the same results after rebuilding the updated `main` entrypoint. The release sequence also reproduced the same results on a fresh-home rerun after adding an isolated working directory and clearing profile overrides. ### Reproduction Use a disposable home that contains an aligned Claude Code MCP registration and no shared REA skill. The following executed script creates that state itself, compares all seven installed skill files with the packaged bundle, checks the selected client explicitly, repeats the affected command, and then tests the shared-destination control. Save it as `reproduce-skill-setup.mjs` outside the checkout and run `node reproduce-skill-setup.mjs /absolute/path/to/built/rea`. It removes the trial home after collecting results. The same script accepts the package root of a separately installed published release. ```javascript import {mkdtempSync, existsSync, readFileSync, rmSync} from 'node:fs'; import {join,dirname} from 'node:path'; import {spawnSync} from 'node:child_process'; const root=process.argv[2]; if (!root) throw new Error('Pass the absolute path to a built REA checkout or extracted package'); const home=mkdtempSync('/tmp/agent-work.'); const env={...process.env,HOME:home,PATH:dirname(process.execPath)+':'+process.env.PATH}; for(const key of ['CLAUDE_CONFIG_DIR','CODEX_HOME','COPILOT_HOME','OPENCODE_CONFIG','OPENCODE_CONFIG_DIR','XDG_CONFIG_HOME','GEMINI_CLI_HOME','GEMINI_CLI_SYSTEM_SETTINGS_PATH','GEMINI_CLI_SYSTEM_DEFAULTS_PATH','GEMINI_CLI_TRUSTED_FOLDERS_PATH','QWEN_HOME','GROK_HOME','PI_CODING_AGENT_DIR','PI_CONFIG_DIR','HERMES_HOME','SAND_DATA_ROOT','APPDATA','OMP_PROFILE','PI_PROFILE']) delete env[key]; const cli=root+'/scripts/rea.mjs'; const run=(args)=>{const r=spawnSync(process.execPath,[cli,...args],{env,cwd:home,encoding:'utf8',timeout:40000});let v;try{v=JSON.parse(r.stdout)}catch{};return {args,exit:r.status,error:r.error?.message,stdout:v??r.stdout,stderr:r.stderr}}; const project=(result)=>({args:result.args,exit:result.exit,status:result.stdout.status,plannedActions:result.stdout.plannedActions?.map(a=>({id:a.id,kind:a.kind})),appliedActions:result.stdout.appliedActions,scope:result.stdout.doctor?.scope??result.stdout.scope,skill:result.stdout.doctor?.identity?.skill??result.stdout.identity?.skill,healthy:result.stdout.doctor?.healthy??result.stdout.healthy,scopeChecks:result.stdout.scope_checks?.map(({name,ok,classification})=>({name,ok,classification})),remediation:result.stdout.remediation}); try { const registration=run(['setup','--client','claude_code','--skill=false','--yes','--json']); const setup=run(['setup','--skill-client','claude_code','--yes','--json']); const files=['SKILL.md','references/connection-and-recovery.md','references/native-and-artifacts.md','references/javascript-applications.md','references/android-applications.md','references/runtime-observation.md','references/evidence-workflows.md']; const byteAlignment=files.map(path=>({path,matches:readFileSync(join(home,'.claude/skills/reverse-engineer-anything',path)).equals(readFileSync(join(root,'skills/reverse-engineer-anything',path)))})); const result={node:process.version,registration:project(registration),setup:project(setup),byteAlignment,claudeSkillExists:existsSync(join(home,'.claude/skills/reverse-engineer-anything/SKILL.md')),sharedSkillExists:existsSync(join(home,'.agents/skills/reverse-engineer-anything/SKILL.md')),doctorClaude:project(run(['doctor','--client','claude_code','--skill','--json'])),rerun:project(run(['setup','--skill-client','claude_code','--yes','--json'])),controlShared:project(run(['setup','--skill-client','shared','--yes','--json']))}; console.log(JSON.stringify(result,null,2)); } finally { rmSync(home,{recursive:true,force:true}); } ``` The relevant CLI sequence inside that isolated environment is: ```text rea setup --client claude_code --skill=false --yes --json rea setup --skill-client claude_code --yes --json rea doctor --client claude_code --skill --json rea setup --skill-client claude_code --yes --json rea setup --skill-client shared --yes --json ``` ### Expected behavior Skill-only setup should verify the client skill copy selected by `--skill-client`, report its aligned identity, return `ready` and exit 0 after a successful installation or no-change rerun. A missing unselected shared copy and the absence of optional Hopper should not make that selected scope fail. The command should keep registration selection independent from skill destination selection. ### Impact and scope A supported client-only skill refresh reports failure after successful installation, including on a no-change rerun. This disrupts setup and maintenance automation while the installed client skill remains usable. The verified workaround is to check readiness with the explicit client-scoped doctor command. Provider execution and native client skill discovery were not exercised. ### REA version The isolated CLI sequence ran on current `main` at revision `693ed332b58d05192f55b8192d2c0c4bc4f4824a`, package version 6.4.0, and on a separately installed published npm `rea-agents@6.4.0` artifact. ### Runtime and platform Both ran on macOS 27.0 arm64 with Node.js v26.10.0, which the package's runtime engine range accepts. The source checkout used locked dependencies installed with `npm ci --ignore-scripts` and a successful `npm run build:cached`; the release used a clean `npm install --ignore-scripts` dependency installation. Each CLI sequence used a fresh temporary home and working directory with client-directory overrides removed and the direct Node executable directory first on PATH. No client login, target binary or analysis engine was required. ### Target and artifact context No target artifact is required; this is a standalone client skill setup and readiness sequence. ### Interface Package or setup ### Earliest failure stage Setup or provider admission ### Relevant output or evidence - Expected source: `src/cli/setupCommands.ts:65-69` defines independent client skill destination selection; `docs/installation.md:329-338,365-367` describes selected skill copies, identity readiness and setup's final checks. `src/application/UpdateMaintenance.ts:114-120` also emits the affected independent skill-refresh command. - Failure source: The inline production CLI probe records successful byte-aligned installation followed by false missing identity and a no-change failure. `src/application/Setup.ts:128,314-326,516-528` retains the chosen skill destination for writing but leaves it out of the final readiness clients; `src/application/Doctor.ts:204-209` uses those clients for skill identity, and `src/application/SupportedClients.ts:614-615` maps an empty selection to the shared root. - Evidence provenance: observed - Local verification: reproduced - Reproduction completeness: complete Evidence provenance details: observed production CLI behavior in isolated temporary homes on the source build and separately installed release; source tracing explains the mismatched final check. Local verification details: reproduced on both tested artifacts, with registration, selected-doctor, file-alignment and shared-destination controls. Reproduction completeness details: complete for the standalone client-only refresh sequence above. Pinned source breadcrumbs: [skill selection and final setup check](https://github.com/morluto/rea/blob/693ed332b58d05192f55b8192d2c0c4bc4f4824a/src/application/Setup.ts#L314), [doctor selection](https://github.com/morluto/rea/blob/693ed332b58d05192f55b8192d2c0c4bc4f4824a/src/application/Doctor.ts#L204), and [maintenance refresh command](https://github.com/morluto/rea/blob/693ed332b58d05192f55b8192d2c0c4bc4f4824a/src/application/UpdateMaintenance.ts#L114). This differs from a wrong install destination or an omitted skill bundle: the chosen client receives the complete correct files. The independent final readiness result is the failed contract. ### Typed outcome or recovery expected The client-only install and no-change rerun should return `ready`, exit 0 and an aligned selected skill identity. ### Additional context Repeat the isolated registered-client sequence with no shared skill present. Require client-only skill setup and its no-change rerun to return `ready`, exit 0 and an aligned selected skill identity; require all seven files to remain byte-aligned with the package. Keep the explicit client-scoped doctor and shared-destination controls passing. Also verify that a genuinely missing or damaged selected client skill still produces a meaningful failure, and that restoration does not silently add an unselected shared copy or change unrelated registrations. ### Triage assessment - Impact level: P2 - Assessment status: supported - Impact basis: A supported client-only skill refresh reports failure and unrelated Hopper remediation after successful installation, including on repeated no-change runs. This disrupts setup/maintenance automation while the installed client skill itself remains usable. - Workaround status: available - Workaround basis: With the existing aligned registration, the executed `doctor --client claude_code --skill --json` command returned exit 0 and verified the installed selected skill without changing files. Users can use that result to check readiness after the false setup failure; it does not correct setup's own exit status.
bsakaguchi 2026-10-15 18:26:18 +00:00
Author
Owner

@CassieFox23 commented on GitHub (Oct 11, 2026):

TL;DR: Yes, this happens on Linux. The skill installs, but setup says needs_human and exits 1. Doctor says the skill is fine.

Build Setup Doctor Setup again
main e36c82bec exit 1 exit 0 exit 1
693ed332b (issue's revision) exit 1 exit 0 exit 1
npm 6.4.0 exit 1 exit 0 exit 1

The wrong field is status, with doctor.identity.skill.state set to missing. The doctor.scope.clients list is empty. By reading the code, an empty list sends the final skill check to the shared folder.

Not run

Whether Claude Code finds the skill, plus macOS and the Ghidra and IDA providers.

Thanks, coygeek, for the clear script.

Commands

Each ran with env -i, a scratch HOME, and an empty working folder.

rea setup --client claude_code --skill=false --yes --json
rea setup --skill-client claude_code --yes --json
rea doctor --client claude_code --skill --json
rea setup --skill-client claude_code --yes --json
rea setup --skill-client shared --yes --json

All seven skill files matched the package byte for byte. No shared copy appeared after the client-only runs. For npm I used npx --yes rea-agents@6.4.0 from an empty folder.

Code reading (not a test)

In Setup.ts on main e36c82bec, line 337 sets status to ready only if remediation is undefined. Line 483, finalSetupRemediation, returns the Hopper text when doctor.healthy is false. Line 226 builds the final doctor scope from the selected clients. The output shows that list is empty for --skill-client alone. In SupportedClients.ts, line 614 maps an empty list to the shared folder.

Test setup
  • Box: Nobara 44 (Fedora 44 base), Linux 7.2.9
  • CPU: AMD Ryzen 9 5900X, 12 cores / 24 threads
  • RAM: 32 GB DDR4-3600
  • Node: 24.18.0
  • Head: e36c82bec (main), 693ed332b (built too), npm rea-agents 6.4.0

🤖 Generated with Claude Code (Sonnet 5.5, verified by Opus 5.5) 🦊

<!-- gh-comment-id:6106496425 --> @CassieFox23 commented on GitHub (Oct 11, 2026): **TL;DR:** Yes, this happens on Linux. The skill installs, but setup says `needs_human` and exits 1. Doctor says the skill is fine. | Build | Setup | Doctor | Setup again | |---|---|---|---| | main e36c82bec | exit 1 | exit 0 | exit 1 | | 693ed332b (issue's revision) | exit 1 | exit 0 | exit 1 | | npm 6.4.0 | exit 1 | exit 0 | exit 1 | The wrong field is `status`, with `doctor.identity.skill.state` set to `missing`. The `doctor.scope.clients` list is empty. By reading the code, an empty list sends the final skill check to the shared folder. ### Not run Whether Claude Code finds the skill, plus macOS and the Ghidra and IDA providers. Thanks, coygeek, for the clear script. <details> <summary>Commands</summary> Each ran with `env -i`, a scratch HOME, and an empty working folder. ```text rea setup --client claude_code --skill=false --yes --json rea setup --skill-client claude_code --yes --json rea doctor --client claude_code --skill --json rea setup --skill-client claude_code --yes --json rea setup --skill-client shared --yes --json ``` All seven skill files matched the package byte for byte. No shared copy appeared after the client-only runs. For npm I used `npx --yes rea-agents@6.4.0` from an empty folder. </details> <details> <summary>Code reading (not a test)</summary> In `Setup.ts` on main e36c82bec, line 337 sets `status` to `ready` only if `remediation` is undefined. Line 483, `finalSetupRemediation`, returns the Hopper text when `doctor.healthy` is false. Line 226 builds the final doctor scope from the selected clients. The output shows that list is empty for `--skill-client` alone. In `SupportedClients.ts`, line 614 maps an empty list to the shared folder. </details> <details> <summary>Test setup</summary> - Box: Nobara 44 (Fedora 44 base), Linux 7.2.9 - CPU: AMD Ryzen 9 5900X, 12 cores / 24 threads - RAM: 32 GB DDR4-3600 - Node: 24.18.0 - Head: e36c82bec (main), 693ed332b (built too), npm rea-agents 6.4.0 </details> 🤖 Generated with Claude Code (Sonnet 5.5, verified by Opus 5.5) 🦊
Author
Owner

@morluto commented on GitHub (Oct 11, 2026):

Fixed on main in bb508134e. Setup and Doctor retain independently selected skill destinations, including omitted versus explicit empty selections. Public CLI coverage passes for install, no-change rerun, damaged selected copies, repair, and independent registration/skill choices.

<!-- gh-comment-id:6111843423 --> @morluto commented on GitHub (Oct 11, 2026): Fixed on main in [bb508134e](https://github.com/morluto/rea/commit/bb508134efbba392a404b651d6ec05be8b7eac1e). Setup and Doctor retain independently selected skill destinations, including omitted versus explicit empty selections. Public CLI coverage passes for install, no-change rerun, damaged selected copies, repair, and independent registration/skill choices.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#571
No description provided.