Skip to content

woosublee/CLIProxyManager

Repository files navigation

CLIProxyManager

CLIProxyManager main window

CLIProxyManager is a macOS menu bar app for managing a local CLIProxyAPI server and the shell functions you use to launch Claude Code with different account and model backends.

It is designed for users who want one place to:

  • Connect Claude OAuth and Codex OAuth profiles.
  • Optionally use a Claude API key stored in macOS Keychain.
  • Start, stop, and configure the bundled CLIProxyAPI server.
  • Install convenient shell functions into ~/.zshrc.
  • Check account, server, and shell setup status from the app.

Requirements

  • macOS 13 or later.
  • Claude Code installed and available on your machine.
  • A Claude account, Codex/OpenAI OAuth account, or Claude API key depending on which shell function you want to use.
  • zsh if you want the app to manage shell functions automatically.

Releases and automatic updates

Canonical local release artifacts are signed with the local cliproxymanager code signing identity and distributed as non-notarized DMGs on GitHub Releases. CLIProxyManager uses Sparkle 2 for automatic updates with this feed URL:

https://github.com/woosublee/CLIProxyManager/releases/latest/download/appcast.xml

Each GitHub Release that should be available through automatic updates must include both:

  • CLIProxyManager-<version>.dmg
  • appcast.xml

Sparkle's EdDSA signature is separate from Apple Developer ID signing. The current automatic-update path can work without Apple Developer ID signing or notarization, but users may still see macOS Gatekeeper or quarantine warnings because the DMG is non-notarized and not signed with an Apple Developer ID certificate.

The app currently keeps the hardened-runtime disable-library-validation entitlement enabled for this non-Developer-ID Sparkle distribution path. Local release builds re-sign the bundled Sparkle framework and helper executables with the local cliproxymanager identity, and without this entitlement macOS can reject the app at launch because the re-signed Sparkle code is not loaded under a matching Developer ID Team ID. Revisit this when Developer ID signing and notarization are introduced.

Quick start

  1. Open CLIProxyManager.

  2. Use Add Provider to connect an account:

    • Claude OAuth for your normal Claude Code subscription login.
    • Codex OAuth for OpenAI/Codex-backed routing through the local proxy.
  3. Review the generated command name and optional nickname, then save.

  4. Open Settings and install shell functions.

  5. Restart your terminal, or run:

    source ~/.zshrc
  6. Use one of the installed shell functions:

    cc
    ccodex
    ccapi

ccapi is installed only when a Claude API key exists in the macOS Keychain.

Shell functions

CLIProxyManager generates shell functions instead of aliases so each command can set the right environment only for that invocation.

cc

Runs Claude Code through the bundled local CLIProxyAPI server using your Claude OAuth profile.

Use this when you want Claude Code to use your normal Claude account or subscription login through the app-managed proxy.

ccodex

Runs Claude Code through the bundled local CLIProxyAPI server using Codex/OpenAI OAuth-backed routing.

CLIProxyManager maps Claude model roles to the Codex model settings saved in the app:

  • Opus role
  • Sonnet role
  • Haiku role

You can configure model, reasoning level, and context window from the Codex account settings sheet.

ccapi

Runs Claude Code directly with a Claude API key from macOS Keychain.

The app does not write the API key into your shell profile. The generated function calls the helper command to read the key at runtime.

cliproxy-manager secret get claude-api-key

If no Claude API key is stored, ccapi is omitted from the installed shell functions.

Settings overview

General

Use General settings to control app appearance and behavior:

  • Light, Dark, or System appearance.
  • Launch at login.
  • Menu bar only mode.
  • Notifications.

Server

Use Server settings to control the local CLIProxyAPI runtime:

  • Listen port.
  • Bind address.
  • Start server on launch.
  • Manual restart after changing server settings.

The app writes the proxy config under:

~/.cliproxy-manager/cliproxyapi/config.yaml

Accounts

Connected provider rows appear after an auth profile exists. Each provider row lets you review the command name, nickname, connection details, and account actions.

Removing an account deletes the corresponding app-managed auth profile from:

~/.cliproxy-manager/auth

Advanced

Advanced settings include log level, log access, and reset actions. Resetting app settings preserves user-managed account data and command names, but resets preferences such as appearance, behavior, server settings, and logging level.

Files managed by the app

CLIProxyManager stores app-managed files under:

~/.cliproxy-manager

Important files and directories:

Path Purpose
~/.cliproxy-manager/config.json App preferences and command settings.
~/.cliproxy-manager/functions.zsh Generated shell functions.
~/.cliproxy-manager/auth/ App-managed OAuth profile files.
~/.cliproxy-manager/logs/ App and proxy logs.
~/.cliproxy-manager/cliproxyapi/ Bundled proxy binary and generated proxy config.

When shell functions are installed, CLIProxyManager adds or updates one managed block in ~/.zshrc that sources ~/.cliproxy-manager/functions.zsh.

Troubleshooting

The command is not found in my terminal

Restart your terminal or run:

source ~/.zshrc

Then check that the shell functions file exists:

ls ~/.cliproxy-manager/functions.zsh

The app reports a shell function name conflict

Another function or alias with the same name already exists in your shell profile. Choose a different command name in CLIProxyManager, or remove the conflicting function from your shell profile.

ccapi is missing

ccapi is generated only when a Claude API key is stored in Keychain. Add or update the API key in the app, then reinstall shell functions.

The local server is not responding

Open CLIProxyManager and check the server status. If needed:

  1. Stop the server.
  2. Start it again.
  3. Confirm the configured port is not already used by another process.
  4. Open logs from the Advanced settings screen.

Codex models are not listed

Start the local server and confirm the Codex OAuth profile is connected. If model loading still fails, enter the model names manually in Codex settings.

Security and credentials

  • Claude API keys are stored in macOS Keychain.
  • OAuth profile files are stored under ~/.cliproxy-manager/auth.
  • Generated shell functions use a local dummy API key only for the app-managed local proxy.
  • Do not commit files from ~/.cliproxy-manager to a repository.

CLIProxyAPI license notice

This app bundles or manages CLIProxyAPI, which is distributed under the MIT License. The CLIProxyAPI license text is included at:

Sources/CLIProxyManagerApp/Resources/Licenses/CLIProxyAPI-LICENSE.txt

When distributing this app with CLIProxyAPI, keep the upstream CLIProxyAPI copyright notice and MIT permission notice in the app bundle and public release materials.

Updating the bundled CLIProxyAPI binary

CLIProxyManager vendors the official macOS arm64 CLIProxyAPI release binary into:

Sources/CLIProxyManagerApp/Resources/cliproxyapi/cliproxyapi

Use the vendoring script with an upstream release version:

scripts/vendor-cliproxyapi.sh 7.0.0

The script downloads router-for-me/CLIProxyAPI release assets from GitHub, verifies the archive against upstream checksums.txt, copies the archive's cli-proxy-api executable as cliproxyapi, and writes:

Sources/CLIProxyManagerApp/Resources/cliproxyapi/cliproxyapi.manifest.json

After updating the binary, verify it is bundled by running:

swift test --filter LicenseResourceTests/testCLIProxyAPIBinaryResourceIsBundled

Commit the updated binary and manifest together.

Cutting an automatic-update release

Automatic-update releases require a Sparkle EdDSA signing key. Keep the local private key in the macOS Keychain using the same naming convention as the other apps:

service: https://sparkle-project.org
account: com.woosublee.CLIProxyManager.sparkle.ed25519
label: Private key for signing Sparkle updates

The committed public key lives in Info.plist as SUPublicEDKey. The private key must not be committed.

To create or export the key pair, download the Sparkle 2.9.2 tarball and run generate_keys:

mkdir -p build
curl -L -o build/Sparkle-2.9.2.tar.xz https://github.com/sparkle-project/Sparkle/releases/download/2.9.2/Sparkle-2.9.2.tar.xz
tar -xf build/Sparkle-2.9.2.tar.xz -C build
build/Sparkle-2.9.2/bin/generate_keys -x build/sparkle_private_key.txt

If generate_keys -x creates a Keychain item whose account is the export file path, copy the same private key value into the canonical item instead of generating a new key:

security add-generic-password \
  -U \
  -s "https://sparkle-project.org" \
  -a "com.woosublee.CLIProxyManager.sparkle.ed25519" \
  -l "Private key for signing Sparkle updates" \
  -D "private key" \
  -j "Public key (SUPublicEDKey value) for this key is:\n\n$(plutil -extract SUPublicEDKey raw Info.plist)" \
  -w "$(cat build/sparkle_private_key.txt)"

Local release tooling reads that canonical Keychain item automatically when SPARKLE_PRIVATE_KEY is unset. This local Keychain path is the default release path. Do not commit build/sparkle_private_key.txt.

Local releases also require a code signing identity named cliproxymanager in the local Keychain. Confirm it before cutting a release:

security find-identity -v -p codesigning | grep '"cliproxymanager"'

The release script does not create code signing certificates automatically. Development and canonical local release builds both use this same cliproxymanager identity by default.

Create and push the release tag from the commit you want to ship:

git tag v1.2.3
git push origin v1.2.3

Then cut the release locally:

scripts/release-local.sh v1.2.3

The local release script validates the v* tag, requires the local cliproxymanager code signing identity, reads CFBundleVersion from Info.plist, builds and verifies the signed DMG, generates build/appcast.xml using the Keychain Sparkle private key, and uploads both release assets with the authenticated gh CLI:

  • CLIProxyManager-<version>.dmg
  • appcast.xml

The GitHub Actions release workflow is a manual fallback for cases where a local release is not practical. Run it with workflow_dispatch and an existing tag. Because CI cannot access the local Keychain, save the same Sparkle private key value in the GitHub secret SPARKLE_PRIVATE_KEY before using that fallback. The fallback workflow may continue to use explicit ad-hoc macOS code signing until a future certificate-import flow is added. Tag pushes do not automatically run the release workflow.

Sparkle updates the app bundle, but it does not automatically overwrite the /usr/local/bin/cliproxy-manager helper. If a release changes the helper, reinstall it from CLIProxyManager after updating.

Provider terms

CLIProxyManager is not an official product of Anthropic, OpenAI, Codex, or any other model provider. It should not be described as endorsed, certified, or guaranteed by those providers.

Users are responsible for using their own accounts and credentials in compliance with each provider's terms, usage policies, and account requirements.

About

macOS menu bar app for managing CLIProxyAPI, Claude Code accounts, and shell launch commands.

Topics

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors