Skip to content
Agentmart
Submit a tool

add-tauri-sidecar

How to bundle an external binary and its dylib dependencies with the Tauri app, patch rpaths, sign everything, and resolve the path at runtime

Skill by robertolupi

IndexedAGPL-3.0★ 7
Write a review

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/robertolupi-add-tauri-sidecar

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

How to bundle an external binary and its dylib dependencies with the Tauri app, patch rpaths, sign everything, and resolve the path at runtime

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/add-tauri-sidecar

What's inside

Skill name
add-tauri-sidecar
Description
How to bundle an external binary and its dylib dependencies with the Tauri app, patch rpaths, sign everything, and resolve the path at runtime
License
AGPL-3.0
Instructions
165 lines in SKILL.md · view on GitHub

Files (1)

  • SKILL.md

SKILL.md (first lines)

# Adding a Tauri Sidecar Binary

Sidecars are external executables bundled inside the `.app` and resolved at runtime. The project already uses this for `llama-server` and `fpcalc`. Follow the same pattern for any new binary.

> **Important**: if the binary depends on dynamic libraries (`.dylib`), there are extra macOS-specific steps around rpath patching and code signing. Read the full skill before starting.

---

## 1. Prepare the binary and its dylibs

### Simple binary (no dylib dependencies)

Copy the binary to `src-tauri/binaries/` with the **target-triple** suffix:

```
src-tauri/binaries/my-tool-aarch64-apple-darwin
```

```bash
chmod +x src-tauri/binaries/my-tool-aarch64-apple-darwin
```

### Binary with dylib dependencies (macOS)

If the binary links against `.dylib` files (check with `otool -L my-tool`), you must:

1. Copy the binary **and all its dylibs** into `src-tauri/binaries/`
2. Patch all hardcoded absolute rpath references to use `@rpath` / `@loader_path` instead
3. Add `@loader_path/../Frameworks` to the RPATH of every file so they find each other when Tauri bundles them into `Contents/Frameworks/`
4. Re-sign everything with your Apple Developer ID

**Use the helper script** `tools/bundle-llama-server.sh` as a reference — it does all of this for llama-server. Create a similar script for your binary.

The key `install_name_tool` operations each file needs:
```bash
# Replace Homebrew lib rpath with @loader_path
install_name_tool -rpath "/opt/homebrew/opt/foo/lib" "@loader_path" "$file"

# Add Frameworks rpath so bundled app finds dylibs in Contents/Frameworks/
install_name_tool -add_rpath "@loader_path/../Frameworks" "$file"

# Patch any remaining absolute /opt/homebrew/... install names → @rpath
install_name_tool -change "/opt/homebrew/opt/foo/lib/libfoo.dylib" "@rpath/libfoo.dylib" "$file"

# Re-sign (required after any install_name_tool modification)
codesign --force --options runtime --sign "Developer ID Application: Roberto Lupi (83BHH8484C)" "$file"
```

---

## 2. Declare in `tauri.conf.json`

```json
"bundle": {
  "externalBin": [
    "binaries/my-tool"
  ],
  "macOS": {
    "frameworks": [
      "binaries/libfoo.dylib",
      "binaries/libbar.0.dylib"
    ]
  }
}
```

**Critical**: dylib dependencies go in `bundle.macOS.frameworks`, **not** `bundle.resources`. The `frameworks` key places them in `Contents/Frameworks/` inside the `.app`, which is the path that `@loader_path/../Frameworks` in the rpath resolves to. Using `resources` puts them in the wrong location and causes a crash at runtime.

The path in `externalBin` is **without** the target-triple suffix — Tauri appends it automatically at bundle time.

---

## 3. Resolve the binary path at runtime in Rust

Do **not** use Tauri's `Command::sidecar()` API — this project resolves sidecar paths manually via `AppHandle`. Follow the pattern from `src-tauri/src/llama.rs` and `src-tauri/src/acoustid.rs`:

```rust
use tauri::{AppHandle, Manager};
use std::path::PathBuf;

fn get_my_tool_path(app: &AppHandle) -> Option<PathBuf> {
    #[cfg(target_arch = "aarch64")]
    const TARGET_ARCH: &str = "aarch64";
    #[cfg(target_arch = "x86_64")]
    const TARGET_ARCH: &str = "x86_64";

    #[cfg(target_os = "macos")]
    const TARGET_OS: &str = "apple-darwin";
    #[cfg(target_os = "linux")]
    const TARGET_OS: &str = "unknown-linux-gnu";
    #[cfg(target_os = "windows")]
    const TARGET_OS: &str = "pc-windows-msvc";

    let triple = format!("{}-{}", TARGET_ARCH, TARGET_OS);
    let filename = format!("my-tool-{}", triple);

    // 1. Next to the executable — production .app where Tauri strips the triple suffix
    if let Ok(exe_path) = std::env::current_exe() {
        if let Some(exe_dir) = exe_path.parent() {
            let p = exe_dir.join("my-tool");       // suffix-stripped name
            if p.exists() { return Some(p); }
            let p = exe_dir.join(&filename);        // triple-suffixed name (fallback)
            if p.exists() { return Some(p); }
        }
    }

    // 2. Resource dir — alternate production layout
    if let Ok(res_dir) = app.path().resource_dir() {
        let p = res_dir.join("binaries").join(&filename);
        if p.exists() { return Some(p); }
    }

    // 3. Dev paths relative to repo root (CARGO_MANIFEST_DIR points to src-tauri/)
    let dev_paths = vec![
        std::path::Path::new("src-tauri/binaries").join(&filename),
        std::path::Path::new("binaries").join(&filename),
    ];
    for p in dev_paths {
        if p.exists() { return Some(p); }

From robertolupi/deep-cuts, AGPL-3.0.

More from robertolupi/deep-cuts

Signals

Stars
7
Forks
1
Open issues
0
Last commit (this folder)
Jun 5, 2026 (4 months ago)
Last release
Jun 8, 2026 (4 months ago)

From GitHub (fetched Oct 24, 2026).

Details

License
AGPL-3.0
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from robertolupi

Cite this page

add-tauri-sidecar skill. Agent Mart. https://agentmart.dev/skills/robertolupi-add-tauri-sidecar (last updated 2026-10-24)