diff --git a/.gitignore b/.gitignore index a14702c..94a2c35 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,7 @@ report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json # Finder (MacOS) folder config .DS_Store + +.direnv +.envrc +.claude diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..810f854 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,67 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +anyclaude is a proxy wrapper for Claude Code that enables using alternative LLM providers (OpenAI, Google, xAI, Azure) through the Anthropic API format. It intercepts Anthropic API calls and translates them to/from the Vercel AI SDK format for the specified provider. + +## Architecture + +The proxy works by: + +1. Spawning a local HTTP server that mimics the Anthropic API +2. Intercepting `/v1/messages` requests containing `/` format +3. Converting Anthropic message format to AI SDK format +4. Routing to the appropriate provider (OpenAI, Google, xAI, Azure) +5. Converting responses back to Anthropic format +6. Setting `ANTHROPIC_BASE_URL` to point Claude Code at the proxy + +Key components: + +- `src/main.ts`: Entry point that sets up providers and spawns Claude with proxy +- `src/anthropic-proxy.ts`: HTTP server that handles request/response translation +- `src/convert-anthropic-messages.ts`: Bidirectional message format conversion +- `src/convert-to-anthropic-stream.ts`: Stream response conversion +- `src/json-schema.ts`: Schema adaptation for different providers + +## Development Commands + +```bash +# Install dependencies +bun install + +# Build the project (creates dist/main.js with shebang) +bun run build + +# The build command: +# 1. Compiles TypeScript to CommonJS for Node.js compatibility +# 2. Adds Node shebang for CLI execution +``` + +## Testing + +Test the proxy manually: + +```bash +# Run in proxy-only mode to get the URL +PROXY_ONLY=true bun run src/main.ts + +# Test with a provider +OPENAI_API_KEY=your-key bun run src/main.ts --model openai/gpt-4 +``` + +## Environment Variables + +Required for each provider: + +- `OPENAI_API_KEY` + optional `OPENAI_API_URL` for OpenAI/OpenRouter +- `GOOGLE_API_KEY` + optional `GOOGLE_API_URL` for Google +- `XAI_API_KEY` + optional `XAI_API_URL` for xAI +- `AZURE_API_KEY` + optional `AZURE_API_URL` for Azure +- `ANTHROPIC_API_KEY` + optional `ANTHROPIC_API_URL` for Anthropic passthrough + +Special modes: + +- `PROXY_ONLY=true`: Run proxy server without spawning Claude Code + diff --git a/README.md b/README.md index fc1cc7c..d34d48d 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Use Claude Code with OpenAI, Google, xAI, and other providers. ```sh # Use your favorite package manager (bun, pnpm, and npm are supported) -$ pnpm install -g anyclaude +$ pnpm install -g anyclaude # anyclaude is a wrapper for the Claude CLI # `openai/`, `google/`, `xai/`, and `anthropic/` are supported diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..8420dc6 --- /dev/null +++ b/flake.lock @@ -0,0 +1,96 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1754498491, + "narHash": "sha256-erbiH2agUTD0Z30xcVSFcDHzkRvkRXOQ3lb887bcVrs=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "c2ae88e026f9525daf89587f3cbee584b92b6134", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1754340878, + "narHash": "sha256-lgmUyVQL9tSnvvIvBp7x1euhkkCho7n3TMzgjdvgPoU=", + "owner": "nixos", + "repo": "nixpkgs", + "rev": "cab778239e705082fe97bb4990e0d24c50924c04", + "type": "github" + }, + "original": { + "owner": "nixos", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs", + "treefmt-nix": "treefmt-nix" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "treefmt-nix": { + "inputs": { + "nixpkgs": "nixpkgs_2" + }, + "locked": { + "lastModified": 1754492133, + "narHash": "sha256-B+3g9+76KlGe34Yk9za8AF3RL+lnbHXkLiVHLjYVOAc=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "1298185c05a56bff66383a20be0b41a307f52228", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..d463bb4 --- /dev/null +++ b/flake.nix @@ -0,0 +1,55 @@ +{ + description = "AnyClaude development environment"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + treefmt-nix.url = "github:numtide/treefmt-nix"; + }; + + outputs = { self, nixpkgs, flake-utils, treefmt-nix }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = nixpkgs.legacyPackages.${system}; + + treefmt = treefmt-nix.lib.evalModule pkgs { + projectRootFile = "flake.nix"; + programs = { + nixpkgs-fmt.enable = true; + shfmt.enable = true; + shellcheck.enable = true; + }; + }; + in + { + # Format the source tree + formatter = treefmt.config.build.wrapper; + + # Check formatting + checks.formatting = treefmt.config.build.check self; + + devShells.default = pkgs.mkShell { + buildInputs = with pkgs; [ + # Primary runtime and package manager + bun + + # Node.js for compatibility (required by some tools) + nodejs_22 + + # Code quality tools (already included by treefmt) + treefmt.config.build.wrapper + + # Version control + git + + # Utilities + jq + ripgrep + bat + ]; + + # Environment variables + NODE_ENV = "development"; + }; + }); +} diff --git a/package.json b/package.json index 486e3e8..9b8edca 100644 --- a/package.json +++ b/package.json @@ -32,4 +32,4 @@ "scripts": { "build": "bun build --target node --outfile dist/main.js ./src/main.ts --format cjs && sed -i '0,/^/s//#!\\/usr\\/bin\\/env node\\n/' ./dist/main.js" } -} \ No newline at end of file +}