https://github.com/kingsword09/droid-patch
CLI tool to patch the droid binary with various modifications.
https://github.com/kingsword09/droid-patch
ai droid patch
Last synced: 3 months ago
JSON representation
CLI tool to patch the droid binary with various modifications.
- Host: GitHub
- URL: https://github.com/kingsword09/droid-patch
- Owner: kingsword09
- License: mit
- Created: 2025-12-11T07:20:01.000Z (6 months ago)
- Default Branch: main
- Last Pushed: 2026-02-27T02:27:57.000Z (4 months ago)
- Last Synced: 2026-02-27T09:45:40.073Z (4 months ago)
- Topics: ai, droid, patch
- Language: TypeScript
- Homepage: https://www.npmjs.com/package/droid-patch
- Size: 416 KB
- Stars: 32
- Watchers: 0
- Forks: 5
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# droid-patch
English | [简体中文](./README.zh-CN.md)
CLI tool to patch the droid binary with various modifications.
## Installation
```bash
npm install -g droid-patch
# or use directly with npx
npx droid-patch --help
```
## Usage
### Patch and Create an Alias
```bash
# Patch with --is-custom and create an alias
npx droid-patch --is-custom droid-custom
# Patch with --skip-login to bypass login requirement
npx droid-patch --skip-login droid-nologin
# Patch with --websearch to enable local search proxy
npx droid-patch --websearch droid-search
# Patch with --websearch --standalone for fully local mode (mock non-LLM APIs)
npx droid-patch --websearch --standalone droid-local
# Patch with --reasoning-effort to enable reasoning for custom models
npx droid-patch --reasoning-effort droid-reasoning
# Combine multiple patches
npx droid-patch --is-custom --skip-login --websearch --reasoning-effort droid-full
# Specify a custom path to the droid binary
npx droid-patch --skip-login -p /path/to/droid my-droid
# Dry run - verify patches without actually applying them
npx droid-patch --skip-login --dry-run droid
# Verbose output
npx droid-patch --skip-login -v droid
```
### Output to a Specific Directory
```bash
# Output patched binary to current directory
npx droid-patch --skip-login -o . my-droid
# Output to a specific directory
npx droid-patch --skip-login -o /path/to/dir my-droid
```
### Available Options
| Option | Description |
| --------------------- | ------------------------------------------------------------------------------------------------------------ |
| `--is-custom` | Patch `isCustom:!0` to `isCustom:!1` (enables context compression for custom models) |
| `--skip-login` | Bypass login by injecting a fake `FACTORY_API_KEY` into the binary |
| `--api-base ` | Replace API URL (standalone: binary patch, max 22 chars; with `--websearch`: proxy forward target, no limit) |
| `--websearch` | External providers mode: Smithery, Google PSE, Tavily, Serper, Brave, SearXNG, DuckDuckGo |
| `--websearch-proxy` | Native provider mode: use model's built-in web_search (requires proxy plugin) |
| `--standalone` | Standalone mode: mock non-LLM Factory APIs (use with `--websearch` or `--websearch-proxy`) |
| `--reasoning-effort` | Enable reasoning effort UI selector for custom models (default `high`; options: `high`, `max`, `xhigh`) |
| `--disable-telemetry` | Disable telemetry and Sentry error reporting |
| `--dry-run` | Verify patches without actually modifying the binary |
| `-p, --path ` | Path to the droid binary (default: `~/.droid/bin/droid`) |
| `-o, --output ` | Output directory for patched binary (creates file without alias) |
| `--no-backup` | Skip creating backup of original binary |
| `-v, --verbose` | Enable verbose output |
### Manage Custom Models
```bash
# List all custom models
npx droid-patch list-models
# Add model interactively
npx droid-patch add-model
# Add model via command line
npx droid-patch add-model \
-m "claude-sonnet-4-20250514" \
-n "Sonnet [proxy]" \
-u "http://127.0.0.1:20002/droid" \
-k "your-api-key" \
-p "anthropic"
# Insert model at specific position
npx droid-patch add-model -i 0 # Interactive, insert at position 0
# Remove model (supports index, ID, or displayName)
npx droid-patch remove-model 0 # By index
npx droid-patch remove-model "custom:Sonnet-[proxy]-1" # By ID
npx droid-patch remove-model "Sonnet [proxy]" # By display name
```
**Model ID Format**: `custom:{DisplayName}-{index}`
- Spaces in `DisplayName` are replaced with `-`
- `index` is the position in the array (starting from 0)
- Example: `displayName: "Opus [proxy]"` → `id: "custom:Opus-[proxy]-0"`
**Important**: When deleting or inserting models, subsequent model IDs are automatically updated (because index changes).
### Manage Aliases and Files
```bash
# List all aliases (shows versions, flags, creation time)
npx droid-patch list
# Remove an alias
npx droid-patch remove
# Remove a patched binary file by path
npx droid-patch remove ./my-droid
npx droid-patch remove /path/to/patched-binary
# Remove aliases by filter
npx droid-patch remove --patch-version=0.4.0 # by droid-patch version
npx droid-patch remove --droid-version=1.0.40 # by droid version
npx droid-patch remove --flag=websearch # by feature flag
# Clear all droid-patch data (aliases, binaries, metadata)
npx droid-patch clear
```
### Update Aliases
When the original droid binary is updated, you can re-apply patches to all aliases:
```bash
# Update all aliases with new droid binary
npx droid-patch update
# Update a specific alias
npx droid-patch update
# Preview without making changes
npx droid-patch update --dry-run
# Use a different droid binary
npx droid-patch update -p /path/to/new/droid
```
The update command reads metadata stored when aliases were created and re-applies the same patches automatically.
### Check Version
```bash
npx droid-patch version
```
## PATH Configuration
When creating an alias (without `-o`), the tool will try to install to a directory already in your PATH (like `~/.local/bin`). If not available, you need to add the aliases directory to your PATH:
```bash
# Add to your shell config (~/.zshrc, ~/.bashrc, etc.)
export PATH="$HOME/.droid-patch/aliases:$PATH"
```
## How It Works
1. **Patching**: The tool searches for specific byte patterns in the droid binary and replaces them with equal-length replacements
2. **Alias Creation** (without `-o`):
- Copies the patched binary to `~/.droid-patch/bins/`
- Creates a symlink in a PATH directory or `~/.droid-patch/aliases/`
- On macOS, automatically re-signs the binary with `codesign`
3. **Direct Output** (with `-o`):
- Saves the patched binary directly to the specified directory
- On macOS, automatically re-signs the binary with `codesign`
## Available Patches
### `--is-custom`
Changes `isCustom:!0` (true) to `isCustom:!1` (false) for custom models.
**Purpose**: This may enable context compression (auto-summarization) for custom models, which is normally only available for official models.
**Note**: Side effects are unknown - test thoroughly before production use.
### `--skip-login`
Replaces all `process.env.FACTORY_API_KEY` references in the binary with a hardcoded fake key `"fk-droid-patch-skip-00000"`.
**Purpose**: Bypass the login/authentication requirement without needing to set the `FACTORY_API_KEY` environment variable.
**How it works**:
- The original code checks `process.env.FACTORY_API_KEY` to authenticate
- After patching, the code directly uses the fake key string, bypassing the env check
- This is a binary-level patch, so it works across all terminal sessions without any environment setup
### `--api-base `
Replace the Factory API base URL. Has different behavior depending on usage:
**1. Standalone (without `--websearch`)**
Binary patch to replace `https://api.factory.ai` with your custom URL.
- **Limitation**: URL must be 22 characters or less (same length as original URL)
- **Use case**: Direct API URL replacement without proxy
```bash
# Valid URLs (<=22 chars)
npx droid-patch --api-base "http://127.0.0.1:3000" droid-local
npx droid-patch --api-base "http://localhost:80" droid-local
# Invalid (too long)
npx droid-patch --api-base "http://my-long-domain.com:3000" droid # Error!
```
**2. With `--websearch`**
Sets the forward target URL for the WebSearch proxy by configuring the `FACTORY_API` variable in the proxy script.
- **No length limitation**: Any valid URL can be used
- **Use case**: Forward non-search requests to your custom LLM backend
```bash
# Forward to custom backend (no length limit)
npx droid-patch --websearch --api-base "http://127.0.0.1:20002" droid-custom
npx droid-patch --websearch --api-base "http://my-proxy.example.com:3000" droid-custom
```
### `--websearch` vs `--websearch-proxy`
**Important**: `--websearch` and `--websearch-proxy` are **mutually exclusive** - you can only use one at a time.
| Mode | Description | Requires |
| ------------------- | ------------------------------------ | --------------------------- |
| `--websearch` | External search providers | Environment variables |
| `--websearch-proxy` | Model's native web_search capability | Proxy plugin + custom model |
### `--websearch`
Enables WebSearch via **external search providers** through a local proxy server.
**Purpose**: Enable WebSearch using third-party search APIs.
**Features**:
- **Multiple search providers** with automatic fallback (Smithery > Google PSE > Tavily > Serper > Brave > SearXNG > DuckDuckGo)
- **Per-instance proxy**: Each droid instance runs its own proxy on an auto-assigned port
- **Auto-cleanup**: Proxy automatically stops when droid exits
- **Forward target**: Use `--api-base` with `--websearch` to forward non-search requests to a custom backend
- **Non-interactive passthrough**: `--version`/`version`, `--help`/`help`, `completion(s)`, `exec` do not start the proxy
**Usage**:
```bash
# Create alias with websearch (uses official Factory API)
npx droid-patch --websearch droid-search
# Create alias with websearch + custom backend
npx droid-patch --websearch --api-base=http://127.0.0.1:20002 droid-custom
# Just run it - everything is automatic!
droid-search
```
### `--websearch-proxy`
Enables WebSearch via **model's native web_search capability** (e.g., Claude's `web_search_20250305` tool).
**Purpose**: Use the LLM provider's built-in web search instead of external providers.
**Requirements**:
1. **Custom model** configured in `~/.factory/settings.json` with a supported provider (`anthropic` or `openai`)
2. **Proxy plugin** ([jixoai/proxy](https://github.com/jixoai/proxy)) to handle Claude Code format conversion
**Features**:
- Reads model configuration from `~/.factory/settings.json`
- Supports Anthropic (`web_search_20250305`) and OpenAI (`web_search`) native tools
- Automatically detects current model's provider
- No external API keys needed (uses your LLM provider's search)
**Usage**:
```bash
# Create alias with native websearch (requires proxy plugin)
npx droid-patch --is-custom --skip-login --websearch-proxy droid-native
# Combine with reasoning effort
npx droid-patch --is-custom --skip-login --reasoning-effort --websearch-proxy droid-full
# Debug mode
DROID_SEARCH_DEBUG=1 droid-native
```
**Proxy Plugin Setup**:
The `--websearch-proxy` mode requires the [jixoai/proxy](https://github.com/jixoai/proxy) plugin to convert between Claude Code format and standard Anthropic API format.
```bash
# Clone and setup the proxy
git clone https://github.com/jixoai/proxy.git
cd proxy
# Install and run (see proxy README for details)
pnpm install
pnpm dev
```
Configure your custom model in `~/.factory/settings.json`:
```json
{
"customModels": [
{
"model": "claude-sonnet-4-20250514",
"id": "custom:Opus-[proxy]-0",
"baseUrl": "http://127.0.0.1:20002/droid",
"apiKey": "your-api-key",
"displayName": "Opus [proxy]",
"provider": "anthropic"
}
],
"sessionDefaultSettings": {
"model": "custom:Opus-[proxy]-0"
}
}
```
**Important**: The `id` field must match the `displayName` pattern:
- Format: `custom:{DisplayName}-{index}` where spaces are replaced with `-`
- Example: `displayName: "Opus [proxy]"` → `id: "custom:Opus-[proxy]-0"`
- The trailing number (`-0`) is the index (starting from 0)
### `--reasoning-effort`
Enables reasoning effort control for custom models by patching the binary to:
1. Set `supportedReasoningEfforts` from `["none"]` to `["high","max","xhigh"]`
2. Set `defaultReasoningEffort` from `"none"` to `"high"`
3. Enable the reasoning effort UI selector (normally hidden for custom models)
4. Bypass validation to allow `xhigh` via settings.json
**Purpose**: Allow custom models to use reasoning effort features that are normally only available for official models.
**How it works**:
- The droid UI shows a reasoning effort selector when `supportedReasoningEfforts.length > 1`
- Custom models are hardcoded with `["none"]`, hiding the selector
- This patch changes the value to `["high","max","xhigh"]` and modifies the UI condition to show the selector
- The reasoning effort setting will be sent to your custom model's API
**Usage**:
```bash
# Enable reasoning effort for custom models
npx droid-patch --reasoning-effort droid-reasoning
# Combine with other patches
npx droid-patch --is-custom --reasoning-effort droid-full
```
**Configuring `xhigh` Reasoning Effort**:
The default reasoning effort is `high`. To use `xhigh` (extra high), edit your settings file:
```bash
# Edit ~/.factory/settings.json
{
"model": "custom:Your-Model-0",
"reasoningEffort": "xhigh",
// ... other settings
}
```
Available values:
| Value | Description |
|-------|-------------|
| `high` | High reasoning effort (default after patching) |
| `max` | Maximum reasoning effort |
| `xhigh` | Extra high reasoning effort |
**Note**: The `xhigh` value bypasses validation and is sent directly to your API. Make sure your custom model/proxy supports this parameter.
### `--standalone`
Enables standalone mode when used with `--websearch`. In this mode, non-LLM Factory APIs are mocked locally instead of being forwarded to Factory servers.
**Purpose**: Reduce unnecessary network requests and enable fully local operation (except for LLM API calls).
**How it works**:
- **Whitelist approach**: Only `/api/llm/a/*` (Anthropic) and `/api/llm/o/*` (OpenAI) are forwarded to upstream
- All other Factory APIs are mocked:
- `/api/sessions/create` → Returns unique local session ID
- `/api/cli/whoami` → Returns 401 (triggers local token fallback)
- `/api/tools/get-url-contents` → Returns 404 (triggers local URL fetch)
- Other APIs → Returns empty `{}` response
**Usage**:
```bash
# Standalone mode with websearch
npx droid-patch --websearch --standalone droid-local
# Combine with other patches for fully local setup
npx droid-patch --is-custom --skip-login --websearch --standalone droid-full-local
```
### `--disable-telemetry`
Disables telemetry data uploads and Sentry error reporting.
**Purpose**: Prevent droid from sending usage data and error reports to Factory servers.
**How it works**:
- Breaks Sentry environment variable checks (`ENABLE_SENTRY`, `VITE_VERCEL_ENV`)
- Makes `flushToWeb()` always return early, preventing any telemetry fetch requests
**Usage**:
```bash
# Disable telemetry only
npx droid-patch --disable-telemetry droid-private
# Combine with other patches
npx droid-patch --is-custom --skip-login --disable-telemetry droid-private
```
---
## WebSearch Configuration Guide
The `--websearch` feature supports multiple search providers. Configure them using environment variables in your shell config (`~/.zshrc`, `~/.bashrc`, etc.).
### Search Provider Priority
The proxy tries providers in this order and uses the first one that succeeds:
| Priority | Provider | Quality | Free Tier | Setup Difficulty |
| -------- | ------------ | --------- | --------------------- | ---------------- |
| 1 | Smithery Exa | Excellent | Free (via Smithery) | Easy |
| 2 | Google PSE | Very Good | 10,000/day | Medium |
| 3 | Tavily | Very Good | Free credits (varies) | Easy |
| 4 | Serper | Very Good | 2,500 free credits | Easy |
| 5 | Brave Search | Good | 2,000/month | Easy |
| 6 | SearXNG | Good | Unlimited (self-host) | Hard |
| 7 | DuckDuckGo | Basic | Unlimited | None |
---
## 1. Smithery Exa (Recommended)
[Smithery Exa](https://smithery.ai/server/exa) provides high-quality semantic search results through the MCP protocol. Smithery acts as a free proxy to the Exa search API.
### Setup Steps
1. **Create a Smithery Account**
- Go to [smithery.ai](https://smithery.ai)
- Sign up for a free account
2. **Get Your API Key**
- Navigate to your account settings
- Copy your API key
3. **Get Your Profile ID**
- Go to [smithery.ai/server/exa](https://smithery.ai/server/exa)
- Your profile ID is shown in the connection URL or settings
4. **Configure Environment Variables**
```bash
# Add to ~/.zshrc or ~/.bashrc
export SMITHERY_API_KEY="your_api_key_here"
export SMITHERY_PROFILE="your_profile_id"
```
### Pricing
- **Free** through Smithery (Smithery proxies the Exa API at no cost)
- Note: The official Exa API (exa.ai) is paid, but Smithery provides free access
---
## 2. Google Programmable Search Engine (PSE)
Google PSE provides high-quality search results with a generous free tier.
### Setup Steps
#### Step 1: Create a Programmable Search Engine
1. Go to [Google Programmable Search Engine Console](https://cse.google.com/all)
2. Click **"Add"** to create a new search engine
3. Configure:
- **Sites to search**: Enter `*` to search the entire web
- **Name**: Give it a descriptive name (e.g., "Web Search")
4. Click **"Create"**
5. Click **"Control Panel"** for your new search engine
6. Copy the **Search engine ID (cx)** - looks like `017576662512468239146:omuauf_lfve`
#### Step 2: Get an API Key
1. Go to [Google Cloud Console](https://console.cloud.google.com/)
2. Create a new project or select an existing one
3. Enable the **Custom Search API**:
- Go to **"APIs & Services"** > **"Library"**
- Search for **"Custom Search API"**
- Click **"Enable"**
4. Create credentials:
- Go to **"APIs & Services"** > **"Credentials"**
- Click **"Create Credentials"** > **"API Key"**
- Copy the API key
#### Step 3: Configure Environment Variables
```bash
# Add to ~/.zshrc or ~/.bashrc
export GOOGLE_PSE_API_KEY="AIzaSy..." # Your API key
export GOOGLE_PSE_CX="017576662512468239146:omuauf_lfve" # Your Search engine ID
```
### Free Tier Limits
- **10,000 queries/day** free
- Max 10 results per query
- After limit: $5 per 1,000 queries
---
## 3. Tavily
[Tavily](https://tavily.com/) provides an easy-to-use web search API.
### Setup Steps
1. **Create an Account**
- Go to [tavily.com](https://tavily.com/)
- Sign up for an account
2. **Get Your API Key**
- Navigate to your dashboard / API settings
- Copy your API key
3. **Configure Environment Variable**
```bash
# Add to ~/.zshrc or ~/.bashrc
export TAVILY_API_KEY="your_api_key_here"
```
---
## 4. Serper
[Serper](https://serper.dev) provides Google search results through an easy-to-use API.
### Setup Steps
1. **Create an Account**
- Go to [serper.dev](https://serper.dev)
- Sign up for a free account
2. **Get Your API Key**
- After signing in, your API key is displayed on the dashboard
- Copy the API key
3. **Configure Environment Variable**
```bash
# Add to ~/.zshrc or ~/.bashrc
export SERPER_API_KEY="your_api_key_here"
```
### Free Tier
- **2,500 free credits** on signup
- 1 credit = 1 search query
- Paid plans available for more usage
---
## 5. Brave Search
[Brave Search API](https://brave.com/search/api/) provides privacy-focused search results.
### Setup Steps
1. **Create an Account**
- Go to [brave.com/search/api](https://brave.com/search/api/)
- Click **"Get Started"**
2. **Subscribe to a Plan**
- Choose the **Free** plan (2,000 queries/month)
- Or a paid plan for more queries
3. **Get Your API Key**
- Go to your API dashboard
- Copy your API key
4. **Configure Environment Variable**
```bash
# Add to ~/.zshrc or ~/.bashrc
export BRAVE_API_KEY="BSA..."
```
### Free Tier
- **2,000 queries/month** free
- Rate limit: 1 query/second
- Paid plans start at $5/month for 20,000 queries
---
## 6. SearXNG (Self-Hosted)
[SearXNG](https://github.com/searxng/searxng) is a free, privacy-respecting metasearch engine you can self-host.
### Setup Steps
#### Option A: Use a Public Instance
You can use a public SearXNG instance, but availability and reliability vary.
```bash
# Example public instance (check if it's available)
export SEARXNG_URL="https://searx.be"
```
Find public instances at [searx.space](https://searx.space/)
#### Option B: Self-Host with Docker
1. **Run SearXNG with Docker**
```bash
docker run -d \
--name searxng \
-p 8080:8080 \
-e SEARXNG_BASE_URL=http://localhost:8080 \
searxng/searxng
```
2. **Configure Environment Variable**
```bash
# Add to ~/.zshrc or ~/.bashrc
export SEARXNG_URL="http://localhost:8080"
```
### Advantages
- Unlimited searches
- No API key required
- Privacy-focused
- Aggregates results from multiple search engines
### Disadvantages
- Requires self-hosting for reliability
- Public instances may be slow or unavailable
---
## 7. DuckDuckGo (Default Fallback)
DuckDuckGo is used automatically as the final fallback when no other providers are configured or available.
### Configuration
**No configuration required!** DuckDuckGo works out of the box.
### Limitations
- HTML scraping (less reliable than API)
- Basic results compared to other providers
- May be rate-limited with heavy use
---
## Quick Configuration Examples
### Minimal Setup (Free, No API Keys)
Just use DuckDuckGo fallback:
```bash
npx droid-patch --websearch droid-search
droid-search # Works immediately with DuckDuckGo
```
### Recommended Setup (Best Quality)
```bash
# Add to ~/.zshrc or ~/.bashrc
export SMITHERY_API_KEY="your_smithery_key"
export SMITHERY_PROFILE="your_profile_id"
# Fallback: Google PSE
export GOOGLE_PSE_API_KEY="your_google_key"
export GOOGLE_PSE_CX="your_search_engine_id"
```
### Budget-Friendly Setup (All Free)
```bash
# Add to ~/.zshrc or ~/.bashrc
# Option 1: Google PSE (10,000/day free)
export GOOGLE_PSE_API_KEY="your_google_key"
export GOOGLE_PSE_CX="your_search_engine_id"
# Option 2: Tavily (free credits vary)
export TAVILY_API_KEY="your_tavily_key"
# Option 3: Serper (2,500 free credits)
export SERPER_API_KEY="your_serper_key"
# Option 4: Brave (2,000/month free)
export BRAVE_API_KEY="your_brave_key"
# DuckDuckGo is always available as final fallback
```
---
## Debug Mode
Enable detailed logging to troubleshoot search issues:
```bash
export DROID_SEARCH_DEBUG=1
droid-search
```
---
## Examples
```bash
# Quick start: create droid with websearch (external providers)
npx droid-patch --websearch droid-search
droid-search # Just works!
# Full-featured droid with external websearch
npx droid-patch --is-custom --skip-login --websearch --reasoning-effort droid-full
# Native websearch via proxy plugin (requires jixoai/proxy)
npx droid-patch --is-custom --skip-login --websearch-proxy droid-native
# Native websearch + reasoning effort
npx droid-patch --is-custom --skip-login --reasoning-effort --websearch-proxy droid-native-full
# Standalone mode: websearch + mock non-LLM APIs
npx droid-patch --websearch --standalone droid-local
# Privacy mode: disable telemetry
npx droid-patch --disable-telemetry droid-private
# Full local setup: all features combined (external websearch)
npx droid-patch --is-custom --skip-login --websearch --standalone --disable-telemetry droid-full-local
# Full local setup with native websearch
npx droid-patch --is-custom --skip-login --websearch-proxy --standalone --disable-telemetry droid-native-local
# Websearch with custom backend
npx droid-patch --websearch --api-base=http://127.0.0.1:20002 droid-custom
# Create a standalone patched binary in current directory
npx droid-patch --skip-login -o . my-droid
./my-droid --version
# List all aliases with version info
npx droid-patch list
# Clean up
npx droid-patch remove droid-search # remove single alias
npx droid-patch remove --flag=websearch # remove all websearch aliases
npx droid-patch remove --flag=standalone # remove all standalone aliases
npx droid-patch remove --patch-version=0.4.0 # remove by droid-patch version
npx droid-patch clear # remove everything
```
## License
MIT