Development
The host needs Docker, Make, Git and a shell. Everything else runs in containers: Dockerfile.dev builds a tools image with Node and pnpm and a dev image with the locked dependencies.
Layout
| Path | What it holds |
|---|---|
src/ | The bridge and the opt-in tool installer (TypeScript, Node 24, ESM) |
docker/ | The entrypoint and the Apktool launcher |
Dockerfile | The production image |
Dockerfile.dev | The tools and dev images every Make target runs in |
tests/ | Bridge unit tests, a stand-in MCP server, and the image integration test |
scripts/ | The dependency script, the version script and the fixture download |
.agents/ | The skill, plugin manifests, the OpenClaw plugin and the contributor rules |
docs/ | This site |
Make targets
make help # every target
make lint # tsc, eslint, prettier, shellcheck, hadolint
make format # apply prettier
make test # unit tests, then the image integration test
make test-unit # bridge unit tests only
make build # build psyb0t/reverse-engineer-anything locally
make run # run the bridge on 127.0.0.1:8080 (needs REA_BRIDGE_TOKEN)
make docs # build this site into .testing/docs-site
make version V=X.Y.Z # set the version in VERSION and the Codex manifest
make pkg-update PKG=rea-agents # move to the newest REA that clears the age gate
make clean # drop the test image, the Ghidra cache volume and fixtures
Dependencies
pnpm is the only package manager, pinned with its sha512 in packageManager and checked by corepack. Every third-party npm release must be at least seven days old: release-age-cutoff holds the UTC cutoff, and scripts/pkg.sh turns it into pnpm’s minimumReleaseAge before every resolution.
Change dependencies only through the Make targets:
| Target | Effect |
|---|---|
make pkg-add PKG=name[@X.Y.Z] | Add an exact version. Moves the cutoff to seven days ago. |
make pkg-update PKG=name | Update one package. Moves the cutoff. |
make pkg-upgrade | Update everything. Moves the cutoff. |
make pkg-remove PKG=name | Remove a package. Moves the cutoff. |
make pkg-lock | Regenerate the lockfile under the existing cutoff. |
make audit | Check production dependencies against the advisory database. |
Installs always use --frozen-lockfile --ignore-scripts. After a rea-agents upgrade, check REA’s src/android/JadxRelease.ts at the new tag: if REA pins a new JADX bridge version or digest, update JADX_MCP_VERSION and JADX_MCP_SHA256 in the Dockerfile to match, then run make test.
Tests
make test-unit runs the bridge tests in tests/*.test.ts with node --test. They start the real bridge against tests/fixtures/fake-mcp.ts, a stand-in for rea mcp, and cover configuration, authentication, host checks, sessions, limits and the tool installer.
make test-integration builds the image as reverse-engineer-anything:test, downloads Appium’s ApiDemos APK into tests/.fixtures (checked against a pinned SHA-256), and runs tests/integration/run.sh:
- The REA CLI answers
--help. mcpmode listsinspect_android_packageover stdio.- The skill’s
rea.shwrapper analyzes the APK. - The bridge starts hardened, refuses a missing token with
401, and a real MCP client drives REA’s Android tools through it. - On amd64, a container with
REA_INSTALL=ghidrainstalls Ghidra and analyzes a native binary through the bridge. On arm64 it checks for the refusal instead.
The Ghidra download is cached in the rea-integration-tools volume. make clean removes it.
CI
.github/workflows/pipeline.yml runs on every push, through the shared reusable workflows:
- Every branch:
make lintandmake teston amd64, thenmake test-integrationon a native arm64 runner. The arm64 job waits for the amd64 one, because both share one concurrency group and a second concurrent call would cancel the first. main: after both pass, builds the image forlinux/amd64andlinux/arm64, pusheslatestandsha-<commit>, scans it with Grype (findings go to the Security tab without failing the run). The README badges refresh as soon ascodepasses.v*tags: no checks run again. The pipeline waits for themainrun of the tagged commit to succeed, promotes itssha-<commit>image to the release tag without rebuilding, cuts the GitHub release from the annotated tag message, refreshes the badges, publishes the skill to ClawHub and publishesserver.jsonto the MCP registry.
The runner needs only Docker, Make and Bash. Nothing in lint or tests needs credentials.
Releases
make version V=X.Y.Z writes VERSION and .agents/.codex-plugin/plugin.json. server.json and the OpenClaw plugin keep their 0.0.0 placeholders, and the publish workflows stamp them from the tag. A release is an annotated vX.Y.Z tag on a commit whose main run passed. The CHANGELOG entry is written at release time.
Documentation
This site is docs/, built by GitHub Pages from main with the Just the Docs theme. make docs builds it locally with the same image GitHub uses, into .testing/docs-site. Every page needs front matter with a unique title and a description, and one # heading. Links to files outside docs/ use full GitHub URLs.