# Claudish Codebase Analysis ## Overview **Claudish** is a CLI tool that runs Claude Code with OpenRouter models via a local Anthropic API-compatible proxy server. It's located at `mcp/claudish/` in the repository root and consists of a TypeScript/Bun project. **Current Version:** v1.3.1 ## Directory Structure ``` mcp/claudish/ ├── src/ │ ├── index.ts # Main entry point │ ├── cli.ts # CLI argument parser │ ├── config.ts # Configuration constants │ ├── types.ts # TypeScript interfaces │ ├── claude-runner.ts # Claude Code execution & temp settings │ ├── proxy-server.ts # Hono-based proxy server (58KB file!) │ ├── transform.ts # OpenAI ↔ Anthropic API transformation │ ├── logger.ts # Debug logging │ ├── simple-selector.ts # Interactive model/API key prompts │ ├── port-manager.ts # Port availability checking │ └── adapters/ # Model-specific adapters │ ├── adapter-manager.ts │ ├── base-adapter.ts │ ├── grok-adapter.ts │ └── index.ts ├── package.json # npm dependencies & scripts ├── tsconfig.json # TypeScript config ├── biome.json # Code formatting config └── dist/ # Compiled JavaScript ``` ## Key Components ### 1. Main Entry Point (`src/index.ts`) **Purpose:** CLI orchestration and setup **Key Flow:** 1. Parses CLI arguments via `parseArgs()` 2. Initializes logger if debug mode is enabled 3. Checks if Claude Code is installed 4. Prompts for OpenRouter API key if needed (interactive mode only) 5. Prompts for model selection if not provided (interactive mode only) 6. Reads stdin if `--stdin` flag is set 7. Finds available port 8. Creates proxy server 9. Spawns Claude Code with proxy environment variables 10. Cleans up proxy on exit ### 2. Configuration (`src/config.ts`) **Key Constants:** ```typescript export const ENV = { OPENROUTER_API_KEY: "OPENROUTER_API_KEY", CLAUDISH_MODEL: "CLAUDISH_MODEL", CLAUDISH_PORT: "CLAUDISH_PORT", CLAUDISH_ACTIVE_MODEL_NAME: "CLAUDISH_ACTIVE_MODEL_NAME", // Set by claudish } as const; export const MODEL_INFO: Record = { "x-ai/grok-code-fast-1": { name: "Grok Code Fast", ... }, "openai/gpt-5-codex": { name: "GPT-5 Codex", ... }, "minimax/minimax-m2": { name: "MiniMax M2", ... }, // ... etc } ``` **Available Models (Priority Order):** 1. `x-ai/grok-code-fast-1` (Grok Code Fast) 2. `openai/gpt-5-codex` (GPT-5 Codex) 3. `minimax/minimax-m2` (MiniMax M2) 4. `z-ai/glm-4.6` (GLM-4.6) 5. `qwen/qwen3-vl-235b-a22b-instruct` (Qwen3 VL) 6. `anthropic/claude-sonnet-4.5` (Claude Sonnet) 7. Custom (any OpenRouter model) ### 3. CLI Parser (`src/cli.ts`) **Responsibility:** Parse command-line arguments and environment variables **Environment Variables Supported:** - `OPENROUTER_API_KEY` - OpenRouter authentication (required for non-interactive mode) - `CLAUDISH_MODEL` - Default model (optional) - `CLAUDISH_PORT` - Default proxy port (optional) - `ANTHROPIC_API_KEY` - Placeholder to prevent Claude Code dialog (handled in claude-runner.ts) **Arguments:** - `-i, --interactive` - Interactive mode - `-m, --model ` - Specify model - `-p, --port ` - Specify port - `--json` - JSON output - `--debug, -d` - Debug logging - `--monitor` - Monitor mode (passthrough to real Anthropic API) - `--stdin` - Read prompt from stdin - And many others... **Default Behavior:** - If no prompt provided and not `--stdin`, defaults to interactive mode - In interactive mode, prompts for missing API key and model - In single-shot mode, requires `--model` flag or `CLAUDISH_MODEL` env var ### 4. Claude Runner (`src/claude-runner.ts`) **Purpose:** Execute Claude Code with proxy and manage temp settings **Key Responsibilities:** 1. **Create Temporary Settings File:** - Location: `/tmp/claudish-settings-{timestamp}.json` - Contains: Custom status line command - Purpose: Show model info in Claude Code status line without modifying global settings 2. **Environment Variables Passed to Claude Code:** ```typescript env: { ...process.env, ANTHROPIC_BASE_URL: proxyUrl, // Point to local proxy CLAUDISH_ACTIVE_MODEL_NAME: modelId, // Used in status line ANTHROPIC_API_KEY: placeholder // Prevent dialog (OpenRouter mode) } ``` 3. **Status Line Format:** - Shows: `[directory] • [model] • $[cost] • [context%]` - Uses ANSI colors for visual enhancement - Reads token data from file written by proxy server - Model name comes from `$CLAUDISH_ACTIVE_MODEL_NAME` environment variable 4. **Context Window Tracking:** - Model context sizes hardcoded in `MODEL_CONTEXT` object - Reads cumulative token counts from `/tmp/claudish-tokens-{PORT}.json` - Calculates context percentage remaining - Defaults to 100k tokens for unknown models 5. **Signal Handling:** - Cleans up temp settings file on SIGINT/SIGTERM/SIGHUP - Ensures no zombie processes ### 5. Proxy Server (`src/proxy-server.ts`) **Size:** 58,460 bytes (large file!) **Architecture:** - Built with Hono.js + @hono/node-server - Implements Anthropic API-compatible endpoints - Transforms requests between Anthropic and OpenRouter formats **Key Endpoints:** - `GET /` - Health check - `GET /health` - Alternative health check - `POST /v1/messages/count_tokens` - Token counting - `POST /v1/messages` - Main chat completion endpoint (streaming and non-streaming) **Modes:** 1. **OpenRouter Mode** (default) - Routes requests to OpenRouter API - Uses provided OpenRouter API key - Filters Claude identity claims from system prompts 2. **Monitor Mode** (--monitor flag) - Passes through to real Anthropic API - Logs all traffic for debugging - Extracts API key from Claude Code requests **Key Features:** - CORS headers enabled - Streaming response support - Token counting and tracking - System prompt filtering (removes Claude identity claims) - Error handling with detailed messages **Token File Writing:** ```typescript const tokenFilePath = `/tmp/claudish-tokens-${port}.json`; writeFileSync(tokenFilePath, JSON.stringify({ input_tokens: cumulativeInputTokens, output_tokens: cumulativeOutputTokens, total_tokens: cumulativeInputTokens + cumulativeOutputTokens, updated_at: Date.now() }), "utf-8"); ``` ### 6. Type Definitions (`src/types.ts`) **Main Interfaces:** - `ClaudishConfig` - CLI configuration object - `OpenRouterModel` - Union type of available models - `AnthropicMessage`, `AnthropicRequest`, `AnthropicResponse` - Anthropic API types - `OpenRouterMessage`, `OpenRouterRequest`, `OpenRouterResponse` - OpenRouter API types - `ProxyServer` - Proxy server interface with `shutdown()` method ## How Model Information is Communicated ### Current Mechanism (v1.3.1) 1. **CLI receives model:** From `--model` flag, `CLAUDISH_MODEL` env var, or interactive selection 2. **Model is passed to proxy creation:** ```typescript const proxy = await createProxyServer( port, config.openrouterApiKey, config.model, // <-- Model ID passed here config.monitor, config.anthropicApiKey ); ``` 3. **Model is set as environment variable:** ```typescript env: { CLAUDISH_ACTIVE_MODEL_NAME: modelId, // Set in claude-runner.ts } ``` 4. **Status line reads from environment:** In the temporary settings file, the status line command uses: ```bash printf "... ${YELLOW}%s${RESET} ..." "$CLAUDISH_ACTIVE_MODEL_NAME" ``` ### How Token Information Flows 1. **Proxy server tracks tokens:** - Accumulates input/output tokens during conversation - Writes to `/tmp/claudish-tokens-{PORT}.json` after each request 2. **Status line reads token file:** - Claude runner creates status line command that reads the token file - Calculates remaining context percentage - Displays as part of status line 3. **Environment Variables Used in Status Line:** ```bash CLAUDISH_ACTIVE_MODEL_NAME - The OpenRouter model ID ``` ## Environment Variable Handling Details ### Variables Currently Supported | Variable | Set By | Read By | Purpose | |----------|--------|---------|---------| | `OPENROUTER_API_KEY` | User (.env or prompt) | cli.ts, proxy-server.ts | OpenRouter authentication | | `CLAUDISH_MODEL` | User (.env) | cli.ts | Default model selection | | `CLAUDISH_PORT` | User (.env) | cli.ts | Default proxy port | | `CLAUDISH_ACTIVE_MODEL_NAME` | claude-runner.ts | Status line script | Display model in status line | | `ANTHROPIC_BASE_URL` | claude-runner.ts | Claude Code | Point to local proxy | | `ANTHROPIC_API_KEY` | claude-runner.ts | Claude Code | Prevent authentication dialog | ### Variable Flow Chart ``` User Input (.env, CLI flags) ↓ parseArgs() in cli.ts ↓ ClaudishConfig object ↓ createProxyServer() + runClaudeWithProxy() ↓ Environment variables passed to Claude Code: - ANTHROPIC_BASE_URL → proxy URL - CLAUDISH_ACTIVE_MODEL_NAME → model ID - ANTHROPIC_API_KEY → placeholder ↓ Claude Code spawned with: - Temporary settings file (for status line) - Environment variables - CLI arguments ``` ## Missing Environment Variable Support ### Not Yet Implemented 1. **ANTHROPIC_MODEL** - Not used anywhere in Claudish - Could be used to override model for status line display - Could help Claude Code identify which model is active 2. **ANTHROPIC_SMALL_FAST_MODEL** - Not used anywhere - Could be used for smaller tasks within Claude Code - Not applicable since Claudish uses OpenRouter models 3. **Model Display Name Customization** - No way to provide a friendly display name - Currently always shows the OpenRouter model ID (e.g., "x-ai/grok-code-fast-1") - Could benefit from showing provider + model name (e.g., "xAI Grok Fast") ## Interesting Implementation Details ### 1. Token File Path Convention ```typescript // Uses port number to ensure each Claudish instance has its own token file const tokenFilePath = `/tmp/claudish-tokens-${port}.json`; ``` ### 2. Temporary Settings File Pattern ```typescript // Each instance gets unique temp file to avoid conflicts const tempPath = join(tmpdir(), `claudish-settings-${timestamp}.json`); ``` ### 3. Model Context Hardcoding ```typescript const MODEL_CONTEXT: Record = { "x-ai/grok-code-fast-1": 256000, "openai/gpt-5-codex": 400000, // ... etc with fallback to 100k }; ``` ### 4. Status Line Script Generation - Creates a complex bash script that: - Reads token data from temp file - Calculates context percentage - Formats output with ANSI colors - All embedded in JSON settings file! ### 5. API Key Handling Strategy - OpenRouter mode: Sets placeholder `ANTHROPIC_API_KEY` to prevent Claude dialog - Monitor mode: Deletes `ANTHROPIC_API_KEY` to allow Claude to use native auth - Both: Actually uses the key specified in the proxy or from Claude's request ## Integration Points ### With Claude Code 1. **Temporary Settings File** - Passed via `--settings` flag 2. **Environment Variables** - `ANTHROPIC_BASE_URL`, `CLAUDISH_ACTIVE_MODEL_NAME`, `ANTHROPIC_API_KEY` 3. **Proxy Server** - Running on localhost, acts as Anthropic API 4. **Token File** - Status line reads from `/tmp/claudish-tokens-{PORT}.json` ### With OpenRouter 1. **API Requests** - Proxy transforms Anthropic → OpenRouter format 2. **Authentication** - Uses `OPENROUTER_API_KEY` environment variable 3. **Model Selection** - Any OpenRouter model ID is supported ## Recommendations for Environment Variable Support Based on this analysis, here are recommendations for adding proper environment variable support: ### 1. Add Model Display Name Support ```typescript // In config.ts export const ENV = { // ... existing ANTHROPIC_MODEL: "ANTHROPIC_MODEL", // Display name override CLAUDISH_MODEL_DISPLAY_NAME: "CLAUDISH_MODEL_DISPLAY_NAME", // Custom display name }; ``` ### 2. Modify claude-runner.ts ```typescript // Extract display name from config const displayName = config.modelDisplayName || config.model; // Pass to status line command via environment variable env[ENV.CLAUDISH_MODEL_DISPLAY_NAME] = displayName; ``` ### 3. Update Status Line Script ```bash # Instead of: printf "... ${YELLOW}%s${RESET} ..." "$CLAUDISH_ACTIVE_MODEL_NAME" # Could support: DISPLAY_NAME=${CLAUDISH_MODEL_DISPLAY_NAME:-$CLAUDISH_ACTIVE_MODEL_NAME} printf "... ${YELLOW}%s${RESET} ..." "$DISPLAY_NAME" ``` ### 4. Support ANTHROPIC_MODEL Variable ```typescript // In cli.ts, after parsing CLAUDISH_MODEL const envModel = process.env[ENV.CLAUDISH_MODEL]; const anthropicModel = process.env[ENV.ANTHROPIC_MODEL]; if (!config.model) { config.model = anthropicModel || envModel; } ``` ## Summary Claudish is a well-structured CLI tool that: - ✅ Manages model selection through multiple channels (flags, env vars, interactive prompts) - ✅ Communicates active model to Claude Code via `CLAUDISH_ACTIVE_MODEL_NAME` environment variable - ✅ Tracks tokens in a file for status line consumption - ✅ Uses temporary settings files to avoid modifying global configuration - ✅ Has clear separation of concerns between CLI, proxy, and runner components **Current environment variable handling is functional but could be enhanced with:** - Support for `ANTHROPIC_MODEL` for consistency with Claude Code - Custom display names for models - More flexible model identification system The token file mechanism at `/tmp/claudish-tokens-{PORT}.json` is clever and allows the status line to display real-time token usage without modifying the proxy or Claude Code itself.