Hmbown/CodeWhale · error · ExecError
native accessibility helper needs a built app or Xcode…
Error message
native accessibility helper needs a built app or Xcode Command Line Tools: ${r.stderr} What it means
The macOS computer-use backend compiles a native Objective-C accessibility helper on demand, caching it under ~/.codewhale-cu/bin. When no pre-built app bundle provides the helper and invoking `clang` to build it fails, this error is thrown with clang's stderr. It means the machine cannot compile the helper because the Xcode Command Line Tools are missing or broken.
Solutions
- Install or repair the toolchain: run `xcode-select --install` and accept the license with `sudo xcode-select --license`.
- Verify clang works: `xcode-select -p` and `clang --version` must succeed.
- If Xcode is installed, ensure `xcode-select -s /Applications/Xcode.app/Contents/Developer` points at it and Xcode has finished its first-run component install.
- Clear a corrupt cached/partial helper: remove ~/.codewhale-cu/bin/accessibility-* and retry.
- As a fallback, ship or point the backend at a pre-built helper app so clang compilation is never needed.
Example fix
// before (shell)
native("click", ...)
// error: native accessibility helper needs a built app or Xcode Command Line Tools: clang: error: no developer tools found
// after (shell, one-time setup)
xcode-select --install && clang --version Defensive patterns
Strategy: fallback
Validate before calling
const { execSync } = require('child_process');
function clangAvailable() {
try { execSync('clang --version', { stdio: 'pipe' }); return true; } catch { return false; }
} Try / catch
try {
await startComputerUse();
} catch (e) {
if (String(e.message).includes('needs a built app or Xcode Command Line Tools')) {
console.error('Install toolchain: xcode-select --install');
}
throw e;
} Prevention
- Provision macOS runners with Xcode Command Line Tools before launching automation.
- Check `xcode-select -p` and `clang --version` in environment setup/CI preflight.
- Ship a pre-built helper app to avoid on-machine compilation entirely.
- Clear ~/.codewhale-cu/bin after toolchain upgrades so stale builds are never reused.
When it happens
Trigger: nativeHelper() is called (first use of any native input/capture tool), no cached helper exists at ~/.codewhale-cu/bin/accessibility-<hash>, and the `clang -fobjc-arc ... -o <tmp>` compile exits non-zero (60s timeout or compile/link failure).
Common situations: Fresh macOS installs without Xcode Command Line Tools; running after an Xcode upgrade that invalidates the toolchain; `xcode-select` pointing at a bare Xcode.app requiring license acceptance; PATH lacking clang (no developer directory selected); a corrupted partial build left in the cache dir from a timed-out build.
Understand the failure class
Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.
Related errors
- element does not belong to the bound application —…
- element has no resolved accessibility identity
- element press was not acknowledged
- menu_item_not_found
- no supported accessibility click at
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/a0d6995f3af8fa76.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/plugins/computer-use/src/backends/darwin.mjs:253
if (fs.existsSync(packaged)) helper = packaged;
}
// A source checkout (plugin installs in other hosts) self-compiles an
// unsigned helper, which has no TCC grant. Prefer the installed app's
// signed helper so accessibility and screen-recording grants carry over.
if (!helper || !fs.existsSync(helper)) {
const installed = path.join(os.homedir(), "Applications", "Codewhale Computer Use.app", "Contents", "MacOS", "accessibility");
if (fs.existsSync(installed)) helper = installed;
}
if (!helper || !fs.existsSync(helper)) {
const source = fileURLToPath(new URL("./darwin-accessibility.m", import.meta.url));
const hash = crypto.createHash("sha256").update(fs.readFileSync(source)).update(fs.readFileSync(new URL("./darwin-recording.h", import.meta.url))).update(fs.readFileSync(new URL("./darwin-ocr.h", import.meta.url))).digest("hex").slice(0, 16);
const dir = path.join(os.homedir(), ".codewhale-cu", "bin");
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
helper = path.join(dir, `accessibility-${hash}`);
if (!fs.existsSync(helper)) {
const tmp = `${helper}-${process.pid}`;
const r = await runL("clang", ["-fobjc-arc", "-Os", "-framework", "Cocoa", "-framework", "ApplicationServices", "-framework", "ScreenCaptureKit", "-framework", "AVFoundation", "-framework", "CoreMedia", "-framework", "Vision", source, "-o", tmp], { timeoutMs: 60_000 });
if (r.code !== 0) throw new ExecError(`native accessibility helper needs a built app or Xcode Command Line Tools: ${r.stderr}`, r);
fs.renameSync(tmp, helper);
}
}
return helper;
}
function requireFocusControl() {
if (!state.foregroundInput) throw Object.assign(new ExecError("This action would take keyboard focus and was not sent in background mode. Use an accessibility action, browser control, or a separate computer."), { code: "background_focus_required" });
}
async function native(tool, args = {}) {
// Window-addressed events still borrow keyboard focus. Block before even
// starting an older installed helper, including the app-scoped fallback.
if (["bg_pointer", "bg_key"].includes(tool) || (tool === "pointer_sequence" && args.app_scoped)) requireFocusControl();
// Every resolved target (element center or screen point) is where the
// action lands; tracking it here means the preview cursor follows element
// actions, not just raw pointer events.
if (tool === "type" && !state.foregroundInput && (await native("input_capabilities"))?.background_focus_guard !== 1) {View on GitHub (pinned to 73e0f67d83)