Install REA's skill into ~/.claude/skills in the image

Claude Code sessions in Claude Desktop's Code tab load user skills from
~/.claude/skills, so the reverse-engineer-anything skill is copied there
from the installed rea-agents package and stays in step with REA's
version. Claude Desktop's chat doesn't read that folder; its skills come
from the account.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-02 18:10:35 +01:00
co-authored by Claude Opus 5.5
parent 43ed5f9183
commit e61c004431
2 changed files with 12 additions and 1 deletions
+1 -1
View File
@@ -46,7 +46,7 @@ Early stage. What exists: a single image (`Dockerfile`, `launch-apps.sh`) with C
A program must be open in the CodeBrowser for the tools to return data. Claude Desktop only starts MCP servers after sign-in.
- **ESP32 Flash Loader** (https://github.com/dynacylabs/ghidra-esp32-flash-loader): a Ghidra loader ("ESP32 Flash Image" in *File → Import File*) for ESP32 app images and flash dumps. It reads the partition table at `0x8000`, maps segments to their addresses, adds peripherals from Espressif's SVD files and loads the chip's ROM ELF for symbols. A flash dump is only recognized when it **starts with the bootloader** (ESP32-S/C layouts). Original-ESP32 dumps (bootloader at `0x1000`) are rejected, and trimming the first `0x1000` bytes doesn't help: the loader then finds no partition table at `0x8000`, loads only the bootloader and throws a NullPointerException while still reporting success. Workaround: cut the app partition out of the dump (offsets from the partition table) and import it as an app image. Its tags ship no binaries and the older forks (tslater2006, Ebiroll, saibotk v1.1.0) don't compile against Ghidra 12, so the `esp32-loader-build` stage builds dynacylabs' master at a pinned commit, with its `data/svd` and `ghidra_scripts` submodules fetched over HTTPS at pinned commits and Gradle checked against gradle.org's SHA-256. It is unpacked into `/opt/ghidra/Ghidra/Extensions/esp32`; loaders need no tool config.
- **REA ("Reverse Engineer Anything")**: https://github.com/morluto/rea (MIT, TypeScript), the `rea-agents` npm package, pinned to **6.8.0** with the tarball checked against the registry's integrity hash; its dependencies are locked by the `npm-shrinkwrap.json` it ships. It needs Node.js ≥24.22.1 (official tarball, SHA-256 checked, in `/opt/node`) and procps' `ps`. It uses Ghidra 12.1.x headless through `GHIDRA_INSTALL_DIR` (its own temporary projects, separate from the GUI's) and binwalk 3.1.x through `REA_BINWALK_COMMAND`; Hopper, IDA, Kuna, JADX, unblob, tshark, pwntools and a browser are not installed, and frida (optional, runtime instrumentation) stays unbuilt because npm blocks its install script. Check with `rea doctor --provider ghidra --json`.
- **REA ("Reverse Engineer Anything")**: https://github.com/morluto/rea (MIT, TypeScript), the `rea-agents` npm package, pinned to **6.8.0** with the tarball checked against the registry's integrity hash; its dependencies are locked by the `npm-shrinkwrap.json` it ships. It needs Node.js ≥24.22.1 (official tarball, SHA-256 checked, in `/opt/node`) and procps' `ps`. It uses Ghidra 12.1.x headless through `GHIDRA_INSTALL_DIR` (its own temporary projects, separate from the GUI's) and binwalk 3.1.x through `REA_BINWALK_COMMAND`; Hopper, IDA, Kuna, JADX, unblob, tshark, pwntools and a browser are not installed, and frida (optional, runtime instrumentation) stays unbuilt because npm blocks its install script. Check with `rea doctor --provider ghidra --json`. REA's bundled skill (`reverse-engineer-anything`) is copied from the package into `~/.claude/skills` in the image, for Claude Code sessions in Claude Desktop's Code tab (they load user skills from there). Claude Desktop's chat doesn't read that folder: its skills come from the account (Settings → Capabilities → Skills) and are cached by the app.
Some REA tools run the target (process capture, runtime/Electron observation), so it does **not** run in the Claude Desktop container. `run.sh` starts a second container from the same image (`claude-re-mcp`): `rea mcp --http --host 0.0.0.0 --port 8765`, only the workspace mounted, no display, `--cap-drop ALL`, `no-new-privileges`, and only on the `--internal` network `claude-re-setup-internal` (no route out) under the alias `rea`. The Claude Desktop container is created on the default network plus that internal one, so it can sign in and reach `http://rea:8765/mcp`. REA's HTTP endpoint has no authentication and serves one client session at a time; the internal network is what limits who can reach it. A detached `docker wait` started by `run.sh` stops REA when Claude Desktop's container ends.
- **binwalk and esptool** are CLI tools in the same image (no MCP server yet). The `Dockerfile` has a `binwalk-build` stage adapted from binwalk's own Dockerfile (https://github.com/ReFirmLabs/binwalk) to Ubuntu 24.04, with every source pinned: binwalk at a master commit (3.1.1; the last tag, v3.1.0, is from 2024), Rust toolchain, `dumpifs`/`lzfse`/`dmg2img` commits, and the Python extractors (`jefferson`, `ubi-reader`, `uefi_firmware`, `vmlinux-to-elf`, ...) in `/opt/binwalk-py`. esptool is in `/opt/esptool`. The venvs' entry points are symlinked into `/usr/local/bin` (not their `python`/`pip`). The final stage adds upstream's runtime extractors from apt, sasquatch from onekey-sec's `.deb`, and Kaleido for `binwalk -E -p` (PNG entropy graphs), found via `KALEIDO_PATH`. Upstream publishes no checksums for sasquatch or Kaleido; their SHA-256s were recorded when pinned, amd64 only. `BINWALK_RM_EXTRACTION_SYMLINK=1` avoids dangling symlinks to container paths in extraction output. esptool needs the serial device passed into the container (`--device`) to talk to hardware; that isn't set up.
- **MCP transport.** Claude Desktop starts local MCP servers as stdio subprocesses. GhidraMCP runs in the same container, so `ghidra-mcp` is a plain stdio entry in `claude_desktop_config.json` that reaches Ghidra on `127.0.0.1`. Servers in other containers (so far REA) serve streamable HTTP and are bridged into the stdio config with `mcp-remote` (`--allow-http --transport http-only`), installed in `/opt/mcp-bridge` from the committed `claude-desktop/mcp-bridge/package-lock.json` and started with `/opt/node/bin/node` by absolute path. Use the same pattern for future servers. Avoid mounting the Docker socket into the Claude Desktop container just to `docker exec` MCP servers.
+11
View File
@@ -347,6 +347,17 @@ COPY --chown=${USER_UID}:${USER_GID} ghidra/FrontEndTool.xml ghidra/preferences
COPY --chown=${USER_UID}:${USER_GID} claude-desktop/claude_desktop_config.json \
/home/${USER_NAME}/.config/Claude/claude_desktop_config.json
# REA's skill (workflow instructions) for Claude Code sessions in Claude
# Desktop's Code tab, which load skills from ~/.claude/skills. Copied from
# the installed rea-agents package, so it matches the REA version. Chat in
# Claude Desktop does not read this folder.
RUN install -d -o "${USER_UID}" -g "${USER_GID}" \
"/home/${USER_NAME}/.claude" "/home/${USER_NAME}/.claude/skills" \
&& cp -r /opt/node/lib/node_modules/rea-agents/skills/reverse-engineer-anything \
"/home/${USER_NAME}/.claude/skills/" \
&& chown -R "${USER_UID}:${USER_GID}" "/home/${USER_NAME}/.claude/skills/reverse-engineer-anything" \
&& test -f "/home/${USER_NAME}/.claude/skills/reverse-engineer-anything/SKILL.md"
COPY --chmod=755 launch-apps.sh /usr/local/bin/launch-apps
USER ${USER_NAME}