[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-75001":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":17,"stars7d":18,"stars30d":19,"stars90d":16,"forks30d":16,"starsTrendScore":20,"compositeScore":21,"rankGlobal":10,"rankLanguage":10,"license":10,"archived":22,"fork":22,"defaultBranch":23,"hasWiki":24,"hasPages":22,"topics":25,"createdAt":10,"pushedAt":10,"updatedAt":43,"readmeContent":44,"aiSummary":45,"trendingCount":16,"starSnapshotCount":16,"syncStatus":46,"lastSyncTime":47,"discoverSource":48},75001,"meridian","rynfar\u002Fmeridian","rynfar","Use your Claude Max subscription with OpenCode, Pi, Droid, Aider, Crush, Cline. Proxy that bridges Anthropic's official SDK to enable Claude Max in third-party tools.","https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002F@rynfar\u002Fmeridian",null,"TypeScript",1398,161,5,28,0,16,50,193,48,101.63,false,"main",true,[26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42],"ai-coding","aider","anthropic","bun","charmbracelet","claude","claude-agent-sdk","claude-max","cline","crush-cli","llm","opencode","opencode-plugin","pi-coding-agent","proxy","pylon-orchestrator","whatsapp-automation","2026-06-12 04:01:16","\u003Cp align=\"center\">\n  \u003Cimg src=\"assets\u002Fbanner.svg\" alt=\"Meridian\" width=\"800\"\u002F>\n\u003C\u002Fp>\n\n\u003Cp align=\"center\">\n  \u003Ca href=\"https:\u002F\u002Fgithub.com\u002Frynfar\u002Fmeridian\u002Freleases\">\u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Fv\u002Frelease\u002Frynfar\u002Fmeridian?style=flat-square&color=6366f1&label=release\" alt=\"Release\">\u003C\u002Fa>\n  \u003Ca href=\"https:\u002F\u002Fwww.npmjs.com\u002Fpackage\u002F@rynfar\u002Fmeridian\">\u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fnpm\u002Fv\u002F@rynfar\u002Fmeridian?style=flat-square&color=8b5cf6&label=npm\" alt=\"npm\">\u003C\u002Fa>\n  \u003Ca href=\"#\">\u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fplatform-macOS%20%7C%20Linux%20%7C%20Windows-a78bfa?style=flat-square\" alt=\"Platform\">\u003C\u002Fa>\n  \u003Ca href=\"#\">\u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Flicense-MIT-c4b5fd?style=flat-square\" alt=\"License\">\u003C\u002Fa>\n  \u003Ca href=\"https:\u002F\u002Fdiscord.gg\u002FjP2a2Z92NZ\">\u003Cimg src=\"https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fdiscord-join-5865F2?style=flat-square&logo=discord&logoColor=white\" alt=\"Discord\">\u003C\u002Fa>\n\u003C\u002Fp>\n\n---\n\nMeridian bridges the Claude Code SDK to the standard Anthropic API. No OAuth interception. No binary patches. No hacks. Just pure, documented SDK calls. Any tool that speaks the Anthropic or OpenAI protocol — OpenCode, ForgeCode, Crush, Cline, Aider, Pi, Droid, Open WebUI, Claude Code — connects to Meridian and gets Claude, with session management, streaming, and prompt caching handled natively by the SDK.\n\n> [!NOTE]\n> ### How Meridian works with Anthropic\n>\n> Meridian is built entirely on the [Claude Code SDK](https:\u002F\u002Fdocs.anthropic.com\u002Fen\u002Fdocs\u002Fclaude-code\u002Fsdk). Every request flows through `query()` — the same documented function Anthropic provides for programmatic access. No OAuth tokens are extracted, no binaries are patched, nothing is reverse-engineered.\n>\n> Because we use the SDK, Anthropic remains in full control of prompt caching, context window management, compaction, rate limiting, and authentication. Meridian doesn't bypass these mechanisms — it depends on them. Max subscription tokens flow through the correct channel, governed by the same guardrails Anthropic built into Claude Code.\n>\n> What Meridian adds is a **presentation and interoperability layer**. We translate Claude Code's output into the standard Anthropic API format so developers can connect the editors, terminals, and workflows they prefer. The SDK does the work; Meridian formats the result.\n>\n> **Our philosophy is simple: work within the SDK's constraints, not around them.** The generous limits on Claude Max exist because Anthropic can optimize and manage usage through Claude Code. Meridian respects that by building only on the tools Anthropic provides — no shortcuts, no workarounds that create friction. We believe this is how developers keep the freedom to choose their own frontends while keeping the platform sustainable for everyone.\n\n## Quick Start\n\n```bash\n# 1. Install\nnpm install -g @rynfar\u002Fmeridian\n\n# 2. Authenticate (one time)\nclaude login\n\n# 3. Configure OpenCode plugin (one time — OpenCode users only)\nmeridian setup\n\n# 4. Start\nmeridian\n```\n\nMeridian runs on `http:\u002F\u002F127.0.0.1:3456`. Point any Anthropic-compatible tool at it:\n\n```bash\nANTHROPIC_API_KEY=x ANTHROPIC_BASE_URL=http:\u002F\u002F127.0.0.1:3456 opencode\n```\n\nThe API key value is a placeholder — Meridian authenticates through the Claude Code SDK, not API keys. Most Anthropic-compatible tools require this field to be set, but any value works.\n\n### NixOS \u002F Nix Flake\n\nMeridian provides a Nix flake for declarative installation.\n\n**Add to your flake inputs:**\n\n```nix\n{\n  inputs.meridian.url = \"github:rynfar\u002Fmeridian\";\n}\n```\n\n**Install the package** (via overlay or directly):\n\n```nix\n# Option A: overlay\nnixpkgs.overlays = [ meridian.overlays.default ];\nenvironment.systemPackages = [ pkgs.meridian ];\n\n# Option B: direct reference\nenvironment.systemPackages = [ meridian.packages.${system}.meridian ];\n```\n\n**OpenCode plugin** -- the plugin file is included at `${pkgs.meridian}\u002Flib\u002Fmeridian\u002Fplugin\u002Fmeridian.ts`. Since this path lives in the Nix store, you need to make it available to OpenCode:\n\nIf you generate your OpenCode config from Nix (e.g. via Home Manager), interpolate the path directly:\n\n```nix\n# home-manager example\nxdg.configFile.\"opencode\u002Fopencode.json\".text = builtins.toJSON {\n  plugin = [ \"${pkgs.meridian}\u002Flib\u002Fmeridian\u002Fplugin\u002Fmeridian.ts\" ];\n};\n```\n\nIf you don't manage your OpenCode config through Nix, symlink the plugin to a stable path and reference that instead:\n\n```nix\n# configuration.nix or home-manager\nenvironment.etc.\"meridian\u002Fplugin\u002Fmeridian.ts\".source =\n  \"${pkgs.meridian}\u002Flib\u002Fmeridian\u002Fplugin\u002Fmeridian.ts\";\n```\n\nThen in `~\u002F.config\u002Fopencode\u002Fopencode.json`:\n\n```json\n{ \"plugin\": [\"\u002Fetc\u002Fmeridian\u002Fplugin\u002Fmeridian.ts\"] }\n```\n\n> **Important:** Do not use `meridian setup` on NixOS. It writes an absolute Nix store path (e.g. `\u002Fnix\u002Fstore\u002F...-meridian-1.x.x\u002Flib\u002F...`) into your OpenCode config, which will break on the next `nixos-rebuild switch` or `home-manager switch` when the store path changes. Use one of the approaches above instead.\n\n**Home Manager service** -- run Meridian as a user systemd service:\n\n```nix\n# flake.nix\n{\n  inputs.meridian.url = \"github:rynfar\u002Fmeridian\";\n}\n\n# home-manager config\n{\n  imports = [ meridian.homeManagerModules.default ];\n\n  services.meridian = {\n    enable = true;\n    settings = {\n      port = 3456;\n      host = \"127.0.0.1\";\n      # passthrough = true;\n      # defaultAgent = \"opencode\";\n      # sonnetModel = \"sonnet\";\n    };\n    # Extra env vars not covered by settings\n    # environment = {\n    #   MERIDIAN_MAX_CONCURRENT = \"20\";\n    # };\n  };\n}\n```\n\nThe service starts automatically on login. Manage it with `systemctl --user {start,stop,restart,status} meridian`.\n\nThe plugin path is also available as `config.services.meridian.opencode.pluginPath` for use in your OpenCode config:\n\n```nix\nxdg.configFile.\"opencode\u002Fopencode.json\".text = builtins.toJSON {\n  plugin = [ config.services.meridian.opencode.pluginPath ];\n};\n```\n\n## Why Meridian?\n\nThe Claude Code SDK provides programmatic access to Claude. But your favorite coding tools expect an Anthropic API endpoint. Meridian bridges that gap — it runs locally, accepts standard API requests, and routes them through the SDK. Claude Code does the heavy lifting; Meridian translates the output.\n\n\u003Cp align=\"center\">\n  \u003Cimg src=\"assets\u002Fhow-it-works.svg\" alt=\"How Meridian works\" width=\"920\"\u002F>\n\u003C\u002Fp>\n\n## Features\n\n- **Standard Anthropic API** — drop-in compatible with any tool that supports a custom `base_url`\n- **OpenAI-compatible API** — `\u002Fv1\u002Fchat\u002Fcompletions` and `\u002Fv1\u002Fmodels` for tools that only speak the OpenAI protocol (Open WebUI, Continue, etc.) — no LiteLLM needed, including `image_url` support for data URLs\n- **Session management** — conversations persist across requests, survive compaction and undo, resume after proxy restarts\n- **Streaming** — full SSE streaming with MCP tool filtering\n- **Concurrent sessions** — run parent and subagent requests in parallel\n- **Subagent model selection** — primary agents get 1M context; subagents get 200k, preserving rate-limit budget\n- **Auto token refresh** — expired OAuth tokens are refreshed automatically; requests continue without interruption\n- **Passthrough mode** — forward tool calls to the client instead of executing internally\n- **Multimodal** — images, documents, file attachments, and multimodal tool results pass through to Claude\n- **Multi-profile** — switch between Claude accounts instantly, no restart needed\n- **Telemetry dashboard** — real-time performance metrics at `\u002Ftelemetry`, including token usage and prompt cache efficiency ([`MONITORING.md`](MONITORING.md))\n- **Telemetry persistence** — opt-in SQLite storage for telemetry data that survives proxy restarts, with configurable retention\n- **Prometheus metrics** — `GET \u002Fmetrics` endpoint for scraping request counters and duration histograms\n- **SDK feature toggles** *(experimental)* — unlock Claude Code features (memory, dreaming, CLAUDE.md) for any connected agent\n\n## SDK Feature Toggles (Experimental)\n\nMeridian can expose Claude Code features to any connected agent. Capabilities like auto-memory, dreaming, and CLAUDE.md — normally exclusive to Claude Code — become available to OpenCode, Crush, Droid, and any other harness routed through Meridian. Each agent keeps its own toolchain while gaining access to these additional features.\n\nConfigure per-adapter at **`\u002Fsettings`** in the Meridian web UI. Changes take effect on the next request — no restart needed. Config is persisted to `~\u002F.config\u002Fmeridian\u002Fsdk-features.json`.\n\n### Available features\n\n| Setting | Options | Description |\n|---|---|---|\n| **Claude Code Prompt** | on \u002F off | Include the SDK's built-in system prompt (tool usage rules, safety guidelines, coding best practices) |\n| **Client Prompt** | on \u002F off | Include the system prompt sent by the connecting agent (e.g. OpenCode or Crush instructions) |\n| **CLAUDE.md** | off \u002F project \u002F full | Load instruction files — `off`: none, `project`: `.\u002FCLAUDE.md` only, `full`: `~\u002F.claude\u002FCLAUDE.md` + `.\u002FCLAUDE.md` |\n| **Memory** | on \u002F off | Auto-memory: read and write memories across sessions |\n| **Auto-Dream** | on \u002F off | Background memory consolidation between sessions |\n| **Thinking** | disabled \u002F adaptive \u002F enabled | Extended thinking mode for complex reasoning |\n| **Thinking Passthrough** | on \u002F off | Forward thinking blocks to the client for display |\n| **Shared Memory** | on \u002F off | Share memory directory with Claude Code (`~\u002F.claude`) instead of isolated storage |\n\n### System prompts\n\nThe system prompt controls are independent — any combination works:\n\n- **Both enabled** (recommended): Claude Code instructions come first, followed by your agent's specific instructions. This gives Claude the full context it needs for features like memory and tool use to work correctly.\n- **Claude Code only**: Just the base Claude Code prompt without agent-specific instructions.\n- **Client only**: Just your agent's prompt, passed through as a raw string.\n- **Neither**: No system prompt at all — Claude operates with just the user message.\n\n> **Note:** For features like memory and dreaming to work well, the Claude Code system prompt should be enabled — it contains the instructions Claude needs to read and write memories correctly.\n\n## Passthrough Mode and Tool Calling\n\nThe core question is **who executes the tools** — the SDK or the client?\n\n- **Passthrough mode** (default for OpenCode) — Claude generates tool calls, but Meridian captures them and sends them back to the client for execution. The client runs the tool using its own implementation, with its own sandboxing, file tracking, and UI, then sends the result in the next request. This is how OpenCode, oh-my-opencagent (OMO), and most coding agents work — they have their own read\u002Fwrite\u002Fbash tools and need to stay in control of what runs on the user's machine.\n- **Internal mode** — Claude Code handles everything. The SDK executes tools directly on the host, runs its full agent loop, and returns the final result. This is for clients that are purely chat interfaces (Open WebUI, simple API consumers) with no tool execution of their own.\n\nMost users don't need to configure anything — the adapter sets the right mode automatically. To override:\n\n```bash\nMERIDIAN_PASSTHROUGH=1 meridian   # force passthrough\nMERIDIAN_PASSTHROUGH=0 meridian   # force internal\n```\n\n### How tool calling works in passthrough\n\n1. The client sends a request with tool definitions (read, write, edit, bash, glob, grep)\n2. Meridian registers these as MCP tools so the SDK can generate proper `tool_use` blocks\n3. The SDK produces a tool call → Meridian captures it and returns it to the client\n4. The client executes the tool locally and sends the result back\n\nFor large tool sets (>15 tools), non-core tools are automatically deferred via the SDK's ToolSearch mechanism. Core tools (read, write, edit, bash, glob, grep) are always loaded eagerly. The deferral threshold is configurable with `MERIDIAN_DEFER_TOOL_THRESHOLD`.\n\n### Known limitations\n\n- **Single tool round-trip per request** — in passthrough mode, the SDK is configured with `maxTurns=2` (or 3 for deferred tools). Multi-step agentic loops where Claude needs several consecutive tool calls require the client to re-send after each round.\n- **Blocked tools** — 13 built-in SDK tools (Read, Write, Bash, etc.) are blocked to prevent conflicts with the client's own tools. 15 additional Claude Code-only tools (CronCreate, EnterWorktree, Agent, etc.) are blocked because they require capabilities that external clients don't support.\n- **Subagent extraction** — Meridian parses the client's Task tool description to extract subagent names and build SDK AgentDefinitions. If the client's agent framework uses a non-standard format, subagent routing may not work automatically.\n\n## Multi-Profile Support\n\nMeridian can route requests to different Claude accounts. Each **profile** is a named auth context — a separate Claude login with its own OAuth tokens. Switch between personal and work accounts, or share a single Meridian instance across teams.\n\n### Adding profiles\n\n```bash\n# Add your personal account\nmeridian profile add personal\n# → Opens browser for Claude login\n\n# Add your work account (sign out of claude.ai first, then sign into the work account)\nmeridian profile add work\n```\n\n> **⚠ Important:** Claude's OAuth reuses your browser session. Before adding a second account, sign out of claude.ai and sign into the other account first.\n\n#### Headless \u002F CI: register an OAuth token\n\nWhen a browser isn't available (containers, CI runners, remote shells), generate a long-lived OAuth token with `claude setup-token` and register it as a profile:\n\n```bash\n# Prompt for the token (input is hidden — paste the value from `claude setup-token`)\nmeridian profile add ci --oauth-token\n\n# Or pass it inline\nmeridian profile add ci --oauth-token sk-ant-oat01-...\n```\n\nOAuth-token profiles store the token in `profiles.json` and feed it to the SDK via `CLAUDE_CODE_OAUTH_TOKEN` — no Keychain entry, no browser handshake. To prevent the SDK's 401-recovery from silently falling back to the host's `~\u002F.claude` credentials, OAuth-token profiles also pin `CLAUDE_CONFIG_DIR` to an isolated per-profile directory under `~\u002F.config\u002Fmeridian\u002Fprofiles\u002F\u003Cname>\u002F`. That directory holds only SDK state (sessions, settings) — never `.credentials.json`, since the token is delivered through the env.\n\n### Switching profiles\n\n```bash\n# CLI (while proxy is running)\nmeridian profile switch work\n\n# Per-request header (any agent)\ncurl -H \"x-meridian-profile: work\" ...\n```\n\nYou can also switch profiles from the web UI at `http:\u002F\u002F127.0.0.1:3456\u002Fprofiles` — a dropdown appears in the nav bar on all pages when profiles are configured.\n\n### Profile commands\n\n| Command | Description |\n|---------|-------------|\n| `meridian profile add \u003Cname>` | Add a profile and authenticate via browser |\n| `meridian profile add \u003Cname> --oauth-token [TOKEN]` | Add a headless profile from a `claude setup-token` value (prompts when `TOKEN` is omitted) |\n| `meridian profile list` | List profiles and auth status |\n| `meridian profile switch \u003Cname>` | Switch the active profile (requires running proxy) |\n| `meridian profile login \u003Cname>` | Re-authenticate an expired profile (browser-login profiles only) |\n| `meridian profile remove \u003Cname>` | Remove a profile and its credentials |\n\n### How it works\n\nEach profile stores its credentials in an isolated `CLAUDE_CONFIG_DIR` under `~\u002F.config\u002Fmeridian\u002Fprofiles\u002F\u003Cname>\u002F`. OAuth-token profiles use the same isolated directory layout — but the token itself lives in `~\u002F.config\u002Fmeridian\u002Fprofiles.json` and is fed to the SDK via `CLAUDE_CODE_OAUTH_TOKEN`, so the per-profile dir holds only SDK state (sessions, settings) and never the credential. When a request arrives, Meridian resolves the profile in priority order:\n\n1. `x-meridian-profile` request header (per-request override)\n2. Active profile (set via `meridian profile switch` or the web UI)\n3. First configured profile\n\nSession state is scoped per profile — switching accounts won't cross-contaminate conversation history.\n\n### Environment variable configuration\n\nFor advanced setups (CI, Docker), profiles can also be provided via environment variable:\n\n```bash\nexport MERIDIAN_PROFILES='[\n  {\"id\":\"personal\",\"claudeConfigDir\":\"\u002Fpath\u002Fto\u002Fconfig1\"},\n  {\"id\":\"work\",\"claudeConfigDir\":\"\u002Fpath\u002Fto\u002Fconfig2\"},\n  {\"id\":\"ci\",\"oauthToken\":\"sk-ant-oat01-...\"}\n]'\nexport MERIDIAN_DEFAULT_PROFILE=personal\nmeridian\n```\n\nProfile shapes:\n\n- `claudeConfigDir` — points at a `~\u002F.claude`-style directory; uses Claude Max OAuth from that dir\n- `apiKey` (with optional `baseUrl`) — direct Anthropic API access; sets `ANTHROPIC_API_KEY` \u002F `ANTHROPIC_BASE_URL`\n- `oauthToken` — long-lived token from `claude setup-token`; sets `CLAUDE_CODE_OAUTH_TOKEN`, no config dir needed\n\nWhen `MERIDIAN_PROFILES` is set, it takes precedence over disk-configured profiles. When unset, Meridian auto-discovers profiles from `~\u002F.config\u002Fmeridian\u002Fprofiles.json` on each request.\n\n## Agent Setup\n\n### OpenCode\n\n**Step 1: Run `meridian setup` (required, one time)**\n\n```bash\nmeridian setup\n```\n\nThis adds the Meridian plugin to your OpenCode global config (`~\u002F.config\u002Fopencode\u002Fopencode.json`). The plugin enables:\n\n- **Session tracking** — reliable conversation continuity across requests\n- **Safe model defaults** — Opus uses 1M context (included with Max subscription); Sonnet uses 200k to avoid Extra Usage charges ([details](#configuration))\n- **Subagent model selection** — subagents automatically use `sonnet`\u002F`opus` (200k), preserving rate-limit budget\n\nIf the plugin is missing, Meridian warns at startup and reports `\"plugin\": \"not-configured\"` in the health endpoint.\n\n**Step 2: Start**\n\n```bash\nANTHROPIC_API_KEY=x ANTHROPIC_BASE_URL=http:\u002F\u002F127.0.0.1:3456 opencode\n```\n\nOr set these in your shell profile so they're always active:\n\n```bash\nexport ANTHROPIC_API_KEY=x\nexport ANTHROPIC_BASE_URL=http:\u002F\u002F127.0.0.1:3456\n```\n\n#### oh-my-opencagent (OMO)\n\n[oh-my-opencagent](https:\u002F\u002Fgithub.com\u002Fnicobailey\u002Foh-my-opencagent) adds multi-agent orchestration on top of OpenCode. It works transparently through Meridian with no extra configuration — OMO uses the same OpenCode headers and tool format, so Meridian detects it automatically.\n\nMeridian parses OMO's Task tool descriptions to extract subagent names (explore, code-review, etc.) and builds SDK AgentDefinitions so Claude can route to the correct agent. Internal orchestration markers (`\u003C!-- OMO_INTERNAL_INITIATOR -->`, `[SYSTEM DIRECTIVE: OH-MY-OPENCODE ...]`) are stripped automatically to prevent context leakage.\n\nOMO requires **passthrough mode** (the default for OpenCode) — subagent delegation flows through tool calls that must be forwarded back to the client.\n\n### Crush\n\nAdd a provider to `~\u002F.config\u002Fcrush\u002Fcrush.json`:\n\n```json\n{\n  \"providers\": {\n    \"meridian\": {\n      \"id\": \"meridian\",\n      \"name\": \"Meridian\",\n      \"type\": \"anthropic\",\n      \"base_url\": \"http:\u002F\u002F127.0.0.1:3456\",\n      \"api_key\": \"dummy\",\n      \"models\": [\n        { \"id\": \"claude-sonnet-4-6\", \"name\": \"Claude Sonnet 4.6 (1M)\", \"context_window\": 1000000, \"default_max_tokens\": 64000, \"can_reason\": true, \"supports_attachments\": true },\n        { \"id\": \"claude-opus-4-6\",   \"name\": \"Claude Opus 4.6 (1M)\",   \"context_window\": 1000000, \"default_max_tokens\": 32768, \"can_reason\": true, \"supports_attachments\": true },\n        { \"id\": \"claude-haiku-4-5-20251001\", \"name\": \"Claude Haiku 4.5\", \"context_window\": 200000, \"default_max_tokens\": 16384, \"can_reason\": true, \"supports_attachments\": true }\n      ]\n    }\n  }\n}\n```\n\n```bash\ncrush run --model meridian\u002Fclaude-sonnet-4-6 \"refactor this function\"\ncrush --model meridian\u002Fclaude-opus-4-6       # interactive TUI\n```\n\nCrush is automatically detected from its `Charm-Crush\u002F` User-Agent — no plugin needed.\n\n### Droid (Factory AI)\n\nAdd Meridian as a custom model provider in `~\u002F.factory\u002Fsettings.json`:\n\n```json\n{\n  \"customModels\": [\n    { \"model\": \"claude-sonnet-4-6\",       \"name\": \"Sonnet 4.6 (Meridian)\", \"provider\": \"anthropic\", \"baseUrl\": \"http:\u002F\u002F127.0.0.1:3456\", \"apiKey\": \"x\" },\n    { \"model\": \"claude-opus-4-6\",         \"name\": \"Opus 4.6 (Meridian)\",   \"provider\": \"anthropic\", \"baseUrl\": \"http:\u002F\u002F127.0.0.1:3456\", \"apiKey\": \"x\" },\n    { \"model\": \"claude-haiku-4-5-20251001\", \"name\": \"Haiku 4.5 (Meridian)\", \"provider\": \"anthropic\", \"baseUrl\": \"http:\u002F\u002F127.0.0.1:3456\", \"apiKey\": \"x\" }\n  ]\n}\n```\n\nThen pick any `custom:claude-*` model in the Droid TUI. No plugin needed — Droid is automatically detected.\n\n### Cline\n\n**1. Authenticate:**\n\n```bash\ncline auth --provider anthropic --apikey \"dummy\" --modelid \"claude-sonnet-4-6\"\n```\n\n**2. Set the proxy URL** in `~\u002F.cline\u002Fdata\u002FglobalState.json`:\n\n```json\n{\n  \"anthropicBaseUrl\": \"http:\u002F\u002F127.0.0.1:3456\",\n  \"actModeApiProvider\": \"anthropic\",\n  \"actModeApiModelId\": \"claude-sonnet-4-6\"\n}\n```\n\n**3. Run:**\n\n```bash\ncline --yolo \"refactor the login function\"\n```\n\nNo plugin needed — Cline uses the standard Anthropic SDK.\n\n### Aider\n\n```bash\nANTHROPIC_API_KEY=x ANTHROPIC_BASE_URL=http:\u002F\u002F127.0.0.1:3456 \\\n  aider --model anthropic\u002Fclaude-sonnet-4-6\n```\n\n> **Note:** `--no-stream` is incompatible due to a litellm parsing issue — use the default streaming mode.\n\n### OpenAI-compatible tools (Open WebUI, Continue, etc.)\n\nMeridian speaks the OpenAI protocol natively — no LiteLLM or translation proxy needed.\n\n**`POST \u002Fv1\u002Fchat\u002Fcompletions`** — accepts OpenAI chat format, returns OpenAI completion format (streaming and non-streaming)\n\n- `image_url` parts are supported when provided as **data URLs** (`data:image\u002F...;base64,...`)\n- multimodal tool flows where a tool returns `tool_result.content = [text, image]` are preserved through the structured multimodal path instead of being flattened to text\n\n**`GET \u002Fv1\u002Fmodels`** — returns available Claude models in OpenAI format\n\nPoint any OpenAI-compatible tool at `http:\u002F\u002F127.0.0.1:3456` with any API key value:\n\n```bash\n# Open WebUI: set OpenAI API base to http:\u002F\u002F127.0.0.1:3456, API key to any value\n# Continue: set apiBase to http:\u002F\u002F127.0.0.1:3456 with provider: openai\n# Any OpenAI SDK: set base_url=\"http:\u002F\u002F127.0.0.1:3456\", api_key=\"dummy\"\n```\n\n> **Note:** Multi-turn conversations work by packing prior turns into the system prompt. Each request is a fresh SDK session — OpenAI clients replay full history themselves and don't use Meridian's session resumption.\n\n### ForgeCode\n\nAdd a custom provider to `~\u002Fforge\u002F.forge.toml`:\n\n```toml\n[[providers]]\nid            = \"meridian\"\nurl           = \"http:\u002F\u002F127.0.0.1:3456\u002Fv1\u002Fmessages\"\nmodels        = \"http:\u002F\u002F127.0.0.1:3456\u002Fv1\u002Fmodels\"\napi_key_vars  = \"MERIDIAN_FORGE_KEY\"\nresponse_type = \"Anthropic\"\nauth_methods  = [\"api_key\"]\n\n[session]\nprovider_id = \"meridian\"\nmodel_id    = \"claude-opus-4-6\"\n```\n\nSet the API key env var. Any value works unless you've enabled authentication with `MERIDIAN_API_KEY`, in which case use your auth key here:\n\n```bash\nexport MERIDIAN_FORGE_KEY=x\n```\n\nThen log in and select the model:\n\n```bash\nforge provider login meridian    # enter any value when prompted\nforge config set provider meridian --model claude-opus-4-6\n```\n\nStart Meridian with the ForgeCode adapter:\n\n```bash\nMERIDIAN_DEFAULT_AGENT=forgecode meridian\n```\n\nForgeCode uses reqwest's default User-Agent, so automatic detection isn't possible. The `MERIDIAN_DEFAULT_AGENT` env var tells Meridian to use the ForgeCode adapter for all unrecognized requests. If you run other agents alongside ForgeCode, use the `x-meridian-agent: forgecode` header instead (add `[providers.headers]` to your `.forge.toml`).\n\n### Pi\n\nPi uses the `@mariozechner\u002Fpi-ai` library which supports a configurable `baseUrl` on the model. Add a provider-level override in `~\u002F.pi\u002Fagent\u002Fmodels.json`:\n\n```json\n{\n  \"providers\": {\n    \"anthropic\": {\n      \"baseUrl\": \"http:\u002F\u002F127.0.0.1:3456\",\n      \"apiKey\": \"x\",\n      \"headers\": {\n        \"x-meridian-agent\": \"pi\"\n      }\n    }\n  }\n}\n```\n\nPi mimics Claude Code's User-Agent, so automatic detection isn't possible. The `x-meridian-agent: pi` header in the config above tells Meridian to use the Pi adapter. Alternatively, if Pi is your only agent, you can set `MERIDIAN_DEFAULT_AGENT=pi` as an env var instead.\n\n### Claude Code\n\nClaude Code can point at Meridian like any other Anthropic API client. The\ncommon use case is sharing a single Claude Max subscription from one host\nacross other machines on your network — run Meridian on the box that is\nlogged into Claude Max, then run Claude Code anywhere else against it.\n\n```bash\n# On another machine (or the same one)\nANTHROPIC_AUTH_TOKEN=x ANTHROPIC_BASE_URL=http:\u002F\u002Fmeridian-host:3456 claude\n```\n\n> **Note:** Use `ANTHROPIC_AUTH_TOKEN` (or `ANTHROPIC_API_KEY`) — Claude Code\n> treats both as bearer credentials. Set the value to your `MERIDIAN_API_KEY`\n> if you've enabled authentication, otherwise any string works.\n\n> ⚠️ **Security for multi-machine setups.** If you expose Meridian beyond\n> loopback (e.g. bind to `0.0.0.0` or a LAN IP), **set `MERIDIAN_API_KEY` to a\n> strong secret** and require it on clients. An unprotected network-accessible\n> proxy is a Claude Max credential leak — anyone who can reach the port can\n> burn your subscription.\n\nClaude Code is detected automatically via its `claude-cli\u002F*` User-Agent.\nRequests flow through the Claude Code adapter which:\n\n- Parses the client's real working directory from its `Primary working directory:` system-prompt line so Claude answers path-related questions with your local path, not the proxy host's.\n- Leaves the SDK subprocess cwd on the proxy host (Claude Code's local paths don't exist there).\n- Runs in passthrough mode by default — Claude Code executes its own tools on the machine it runs on; Meridian just forwards tool_use blocks.\n\n### Any Anthropic-compatible tool\n\n```bash\nexport ANTHROPIC_API_KEY=x\nexport ANTHROPIC_BASE_URL=http:\u002F\u002F127.0.0.1:3456\n```\n\n## Tested Agents\n\n| Agent | Status | Notes |\n|-------|--------|-------|\n| [OpenCode](https:\u002F\u002Fgithub.com\u002Fanomalyco\u002Fopencode) | ✅ Verified | Requires `meridian setup` — full tool support, session resume, streaming, subagents |\n| [ForgeCode](https:\u002F\u002Fforgecode.dev) | ✅ Verified | Provider config (see above) — passthrough tool execution, session resume, streaming |\n| [Droid (Factory AI)](https:\u002F\u002Ffactory.ai\u002Fproduct\u002Fide) | ✅ Verified | BYOK config (see above) — full tool support, session resume, streaming |\n| [Crush](https:\u002F\u002Fgithub.com\u002Fcharmbracelet\u002Fcrush) | ✅ Verified | Provider config (see above) — full tool support, session resume, headless `crush run` |\n| [Cline](https:\u002F\u002Fgithub.com\u002Fcline\u002Fcline) | ✅ Verified | Config (see above) — full tool support, file read\u002Fwrite\u002Fedit, bash, session resume |\n| [Aider](https:\u002F\u002Fgithub.com\u002Fpaul-gauthier\u002Faider) | ✅ Verified | Env vars — file editing, streaming; `--no-stream` broken (litellm bug) |\n| [Open WebUI](https:\u002F\u002Fgithub.com\u002Fopen-webui\u002Fopen-webui) | ✅ Verified | OpenAI-compatible endpoints — set base URL to `http:\u002F\u002F127.0.0.1:3456` |\n| [Pi](https:\u002F\u002Fgithub.com\u002Fmariozechner\u002Fpi-coding-agent) | ✅ Verified | models.json config (see above) — requires `MERIDIAN_DEFAULT_AGENT=pi` |\n| [Claude Code](https:\u002F\u002Fdocs.anthropic.com\u002Fen\u002Fdocs\u002Fclaude-code) | ✅ Verified | `ANTHROPIC_BASE_URL` — remote clients share a Max subscription over the network; client CWD preserved in system prompt |\n| [Continue](https:\u002F\u002Fgithub.com\u002Fcontinuedev\u002Fcontinue) | 🔲 Untested | OpenAI-compatible endpoints should work — set `apiBase` to `http:\u002F\u002F127.0.0.1:3456` |\n\nTested an agent or built a plugin? [Open an issue](https:\u002F\u002Fgithub.com\u002Frynfar\u002Fmeridian\u002Fissues) and we'll add it.\n\n## Architecture\n\n```\nsrc\u002Fproxy\u002F\n├── server.ts              ← HTTP orchestration (routes, SSE streaming, concurrency)\n├── adapter.ts             ← AgentAdapter interface\n├── adapters\u002F\n│   ├── detect.ts          ← Agent detection from request headers\n│   ├── opencode.ts        ← OpenCode adapter\n│   ├── forgecode.ts       ← ForgeCode adapter\n│   ├── crush.ts           ← Crush adapter\n│   ├── droid.ts           ← Droid adapter\n│   ├── pi.ts              ← Pi adapter\n│   └── passthrough.ts     ← LiteLLM passthrough adapter\n├── query.ts               ← SDK query options builder\n├── errors.ts              ← Error classification\n├── models.ts              ← Model mapping (sonnet\u002Fopus\u002Fhaiku, agentMode)\n├── tokenRefresh.ts        ← Cross-platform OAuth token refresh\n├── openai.ts              ← OpenAI ↔ Anthropic format translation (pure)\n├── setup.ts               ← OpenCode plugin configuration\n├── session\u002F\n│   ├── lineage.ts         ← Per-message hashing, mutation classification (pure)\n│   ├── fingerprint.ts     ← Conversation fingerprinting\n│   └── cache.ts           ← LRU session caches\n├── profiles.ts            ← Multi-profile: resolve, list, switch auth contexts\n├── profileCli.ts          ← CLI commands for profile management\n├── sessionStore.ts        ← Cross-proxy file-based session persistence\n└── passthroughTools.ts    ← Tool forwarding mode\ntelemetry\u002F\n├── ...\n├── profileBar.ts          ← Shared profile switcher bar\n└── profilePage.ts         ← Profile management page\nplugin\u002F\n└── meridian.ts            ← OpenCode plugin (session headers + agent mode)\n```\n\n### Session Management\n\nEvery incoming request is classified:\n\n| Classification | What Happened | Action |\n|---------------|---------------|--------|\n| **Continuation** | New messages appended | Resume SDK session |\n| **Compaction** | Agent summarized old messages | Resume (suffix preserved) |\n| **Undo** | User rolled back messages | Fork at rollback point |\n| **Diverged** | Completely different conversation | Start fresh |\n\nSessions are stored in-memory (LRU) and persisted to `~\u002F.cache\u002Fmeridian\u002Fsessions.json` for cross-proxy resume.\n\n### Agent Detection\n\nAgents are identified from request headers automatically:\n\n| Signal | Adapter |\n|---|---|\n| `x-meridian-agent` header | Explicit override (any adapter) |\n| `x-opencode-session` or `x-session-affinity` header | OpenCode |\n| `opencode\u002F` User-Agent | OpenCode |\n| `factory-cli\u002F` User-Agent | Droid |\n| `Charm-Crush\u002F` User-Agent | Crush |\n| `litellm\u002F` UA or `x-litellm-*` headers | LiteLLM passthrough |\n| *(anything else)* | `MERIDIAN_DEFAULT_AGENT` env var, or OpenCode |\n\n### Adding a New Agent\n\nImplement the `AgentAdapter` interface in `src\u002Fproxy\u002Fadapters\u002F`. See [`adapters\u002Fopencode.ts`](src\u002Fproxy\u002Fadapters\u002Fopencode.ts) for a reference.\n\n## API Key Authentication\n\nBy default, Meridian binds to `127.0.0.1` and requires no authentication — anyone on localhost can use it. If you expose Meridian over a network (Tailscale, LAN, Docker with port mapping), you can enable API key authentication to prevent unauthorized access.\n\n```bash\nMERIDIAN_API_KEY=your-secret-key meridian\n```\n\nWhen set:\n- All API routes (`\u002Fv1\u002Fmessages`, `\u002Fv1\u002Fchat\u002Fcompletions`, etc.) and admin routes (`\u002Ftelemetry`, `\u002Fmetrics`, `\u002Fprofiles`) require a matching key\n- `\u002F` and `\u002Fhealth` remain open (monitoring tools need unauthenticated health checks)\n- Keys are accepted via `x-api-key` header or `Authorization: Bearer` header\n\nClients just set their `ANTHROPIC_API_KEY` to the shared secret — since most tools already send this header, no workflow changes are needed:\n\n```bash\nANTHROPIC_API_KEY=your-secret-key ANTHROPIC_BASE_URL=http:\u002F\u002Fmeridian-host:3456 opencode\n```\n\n## Configuration\n\n| Variable | Alias | Default | Description |\n|----------|-------|---------|-------------|\n| `MERIDIAN_API_KEY` | — | unset | Shared secret for API key authentication. When set, all API and admin routes require a matching `x-api-key` or `Authorization: Bearer` header. `\u002F` and `\u002Fhealth` remain open. |\n| `MERIDIAN_PORT` | `CLAUDE_PROXY_PORT` | `3456` | Port to listen on |\n| `MERIDIAN_HOST` | `CLAUDE_PROXY_HOST` | `127.0.0.1` | Host to bind to |\n| `MERIDIAN_PASSTHROUGH` | `CLAUDE_PROXY_PASSTHROUGH` | unset | Forward tool calls to client instead of executing |\n| `MERIDIAN_MAX_CONCURRENT` | `CLAUDE_PROXY_MAX_CONCURRENT` | `10` | Maximum concurrent SDK sessions |\n| `MERIDIAN_MAX_SESSIONS` | `CLAUDE_PROXY_MAX_SESSIONS` | `1000` | In-memory LRU session cache size |\n| `MERIDIAN_MAX_STORED_SESSIONS` | `CLAUDE_PROXY_MAX_STORED_SESSIONS` | `10000` | File-based session store capacity |\n| `MERIDIAN_WORKDIR` | `CLAUDE_PROXY_WORKDIR` | `cwd()` | Default working directory for SDK |\n| `MERIDIAN_IDLE_TIMEOUT_SECONDS` | `CLAUDE_PROXY_IDLE_TIMEOUT_SECONDS` | `120` | HTTP keep-alive timeout |\n| `MERIDIAN_TELEMETRY_SIZE` | `CLAUDE_PROXY_TELEMETRY_SIZE` | `1000` | Telemetry ring buffer size |\n| `MERIDIAN_NO_FILE_CHANGES` | `CLAUDE_PROXY_NO_FILE_CHANGES` | unset | Disable \"Files changed\" summary in responses |\n| `MERIDIAN_SONNET_MODEL` | `CLAUDE_PROXY_SONNET_MODEL` | `sonnet` | Sonnet context tier: `sonnet` (200k, default) or `sonnet[1m]` (1M, requires Extra Usage†) |\n| `MERIDIAN_DEFAULT_AGENT` | — | `opencode` | Default adapter for unrecognized agents: `opencode`, `forgecode`, `pi`, `crush`, `droid`, `passthrough`. Requires restart. |\n| `MERIDIAN_PROFILES` | — | unset | JSON array of profile configs (overrides disk discovery). See [Multi-Profile Support](#multi-profile-support). |\n| `MERIDIAN_DEFER_TOOL_THRESHOLD` | — | `15` | Number of tools before non-core tools are deferred via ToolSearch. Set to `0` to disable. |\n| `MERIDIAN_TELEMETRY_PERSIST` | — | unset | Enable SQLite telemetry persistence. Data survives proxy restarts. |\n| `MERIDIAN_TELEMETRY_DB` | — | `~\u002F.config\u002Fmeridian\u002Ftelemetry.db` | SQLite database path (when persistence is enabled) |\n| `MERIDIAN_TELEMETRY_RETENTION_DAYS` | — | `7` | Days to retain telemetry data before cleanup |\n| `MERIDIAN_DEFAULT_PROFILE` | — | *(first profile)* | Default profile ID when no header is sent |\n\n†Sonnet 1M requires Extra Usage on all plans including Max ([docs](https:\u002F\u002Fcode.claude.com\u002Fdocs\u002Fen\u002Fmodel-config#extended-context)). Opus 1M is included with Max\u002FTeam\u002FEnterprise at no extra cost.\n\n## Endpoints\n\n| Endpoint | Description |\n|----------|-------------|\n| `GET \u002F` | Landing page |\n| `POST \u002Fv1\u002Fmessages` | Anthropic Messages API |\n| `POST \u002Fmessages` | Alias for `\u002Fv1\u002Fmessages` |\n| `POST \u002Fv1\u002Fchat\u002Fcompletions` | OpenAI-compatible chat completions |\n| `GET \u002Fv1\u002Fmodels` | OpenAI-compatible model list |\n| `GET \u002Fhealth` | Auth status, mode, plugin status |\n| `POST \u002Fauth\u002Frefresh` | Manually refresh the OAuth token |\n| `GET \u002Ftelemetry` | Performance dashboard |\n| `GET \u002Ftelemetry\u002Frequests` | Recent request metrics (JSON) |\n| `GET \u002Ftelemetry\u002Fsummary` | Aggregate statistics (JSON) |\n| `GET \u002Ftelemetry\u002Flogs` | Diagnostic logs (JSON) |\n| `GET \u002Fmetrics` | Prometheus exposition format metrics |\n| `GET \u002Fprofiles` | Profile management page |\n| `GET \u002Fprofiles\u002Flist` | List profiles with auth status (JSON) |\n| `POST \u002Fprofiles\u002Factive` | Switch the active profile |\n\nHealth response example:\n\n```json\n{\n  \"status\": \"healthy\",\n  \"version\": \"1.34.1\",\n  \"auth\": { \"loggedIn\": true, \"email\": \"you@example.com\", \"subscriptionType\": \"max\" },\n  \"mode\": \"internal\",\n  \"plugin\": { \"opencode\": \"configured\" }\n}\n```\n\n`plugin.opencode` is `\"configured\"` when `meridian setup` has been run, `\"not-configured\"` otherwise.\n\n## Plugins\n\nExtend Meridian's behavior with composable plugins — no core modifications needed.\n\n**Quick start:** Drop a `.ts` or `.js` file in `~\u002F.config\u002Fmeridian\u002Fplugins\u002F` and restart.\n\n```ts\n\u002F\u002F ~\u002F.config\u002Fmeridian\u002Fplugins\u002Fmy-plugin.ts\nexport default {\n  name: \"my-plugin\",\n  onRequest(ctx) {\n    \u002F\u002F modify request context\n    return { ...ctx, systemContext: ctx.systemContext + \"\\nBe concise.\" }\n  },\n}\n```\n\n- **Manage plugins** at `http:\u002F\u002Flocalhost:3456\u002Fplugins`\n- **Reload without restart:** `POST \u002Fplugins\u002Freload`\n- **Full guide:** See [PLUGINS.md](PLUGINS.md)\n\n## CLI Commands\n\n| Command | Description |\n|---------|-------------|\n| `meridian` | Start the proxy server |\n| `meridian setup` | Configure the OpenCode plugin in `~\u002F.config\u002Fopencode\u002Fopencode.json` |\n| `meridian profile add \u003Cname>` | Add a profile and authenticate via browser |\n| `meridian profile add \u003Cname> --oauth-token [TOKEN]` | Add a headless profile from a `claude setup-token` value (prompts when `TOKEN` is omitted) |\n| `meridian profile list` | List all profiles and their auth status |\n| `meridian profile switch \u003Cname>` | Switch the active profile (requires running proxy) |\n| `meridian profile login \u003Cname>` | Re-authenticate an expired profile (browser-login profiles only) |\n| `meridian profile remove \u003Cname>` | Remove a profile and its credentials |\n| `meridian refresh-token` | Manually refresh the Claude OAuth token (exits 0\u002F1) |\n\n## Programmatic API\n\n```typescript\nimport { startProxyServer } from \"@rynfar\u002Fmeridian\"\n\nconst instance = await startProxyServer({\n  port: 3456,\n  host: \"127.0.0.1\",\n  silent: true,\n})\n\n\u002F\u002F instance.server — underlying http.Server\nawait instance.close()\n```\n\n## Docker\n\nClaude Code authentication requires a browser, which isn't available inside containers. Authenticate on your local machine first, then mount the credentials into Docker.\n\n### Single account\n\n```bash\n# 1. Authenticate locally (one time)\nclaude login\n\n# 2. Run with mounted credentials\ndocker run -v ~\u002F.claude:\u002Fhome\u002Fclaude\u002F.claude -p 3456:3456 meridian\n```\n\nMeridian refreshes OAuth tokens automatically — once the credentials are mounted, no further browser access is needed.\n\n### Multiple profiles in Docker\n\nAuthenticate each profile locally, then pass them to Docker via the `MERIDIAN_PROFILES` environment variable:\n\n```bash\n# 1. Authenticate each account locally\nmeridian profile add personal\nmeridian profile add work    # sign out of claude.ai first, sign into work account\n\n# 2. Run Docker with profile configs pointing to mounted credential directories\ndocker run \\\n  -v ~\u002F.config\u002Fmeridian\u002Fprofiles\u002Fpersonal:\u002Fprofiles\u002Fpersonal \\\n  -v ~\u002F.config\u002Fmeridian\u002Fprofiles\u002Fwork:\u002Fprofiles\u002Fwork \\\n  -e 'MERIDIAN_PROFILES=[{\"id\":\"personal\",\"claudeConfigDir\":\"\u002Fprofiles\u002Fpersonal\"},{\"id\":\"work\",\"claudeConfigDir\":\"\u002Fprofiles\u002Fwork\"}]' \\\n  -e MERIDIAN_DEFAULT_PROFILE=personal \\\n  -p 3456:3456 meridian\n```\n\nSwitch profiles at runtime via the `x-meridian-profile` header or `meridian profile switch` (see [Multi-Profile Support](#multi-profile-support)).\n\n### OAuth-token profiles in Docker (no volume mount)\n\nIf you'd rather not mount a credential directory, generate a long-lived OAuth token on the host with `claude setup-token` and pass it as a profile. There's nothing to mount — the token alone is the credential:\n\n```bash\ndocker run \\\n  -e 'MERIDIAN_PROFILES=[{\"id\":\"ci\",\"oauthToken\":\"sk-ant-oat01-...\"}]' \\\n  -e MERIDIAN_DEFAULT_PROFILE=ci \\\n  -p 3456:3456 meridian\n```\n\nThis is the recommended path for CI runners, ephemeral containers, and cross-host deployments where browser-based login isn't reachable. Treat the token like any other secret — inject it via your platform's secret store rather than committing it to your image or compose file.\n\n## Testing\n\n```bash\nnpm test       # unit + integration tests\nnpm run build  # build with bun + tsc\n```\n\n| Tier | What | Speed |\n|------|------|-------|\n| Unit | Pure functions, no mocks | Fast |\n| Integration | HTTP layer with mocked SDK | Fast |\n| E2E | Real proxy + real Claude Max ([`E2E.md`](E2E.md)) | Manual |\n\n## FAQ\n\n**Is this allowed by Anthropic's terms?**\nMeridian uses the official Claude Code SDK — the same SDK Anthropic publishes and documents for programmatic access. It does not intercept credentials, modify binaries, or bypass any authentication. All requests flow through the SDK's own authentication and rate-limiting mechanisms.\n\n**How is this different from using an API key?**\nAPI keys provide direct API access billed per token. Claude Max includes programmatic access through the Claude Code SDK. Meridian translates SDK responses into the standard Anthropic API format, allowing compatible tools to connect through Claude Code.\n\n**What happens if my OAuth token expires?**\nTokens expire roughly every 8 hours. Meridian detects the expiry, refreshes the token automatically, and retries the request — so requests continue transparently. If the refresh fails (e.g. the refresh token has expired after weeks of inactivity), Meridian returns a clear error telling you to run `claude login`.\n\n**Can I trigger a token refresh manually?**\n\n```bash\n# CLI — works whether the proxy is running or not\nmeridian refresh-token\n\n# HTTP — while the proxy is running\ncurl -X POST http:\u002F\u002F127.0.0.1:3456\u002Fauth\u002Frefresh\n```\n\n**I'm hitting rate limits on 1M context. What do I do?**\nMeridian defaults Sonnet to 200k context because Sonnet 1M is always billed as Extra Usage on Max plans — even when regular usage isn't exhausted. This is [Anthropic's intended billing model](https:\u002F\u002Fcode.claude.com\u002Fdocs\u002Fen\u002Fmodel-config#extended-context), not a bug. Set `MERIDIAN_SONNET_MODEL=sonnet[1m]` to opt in if you have Extra Usage enabled and understand the billing implications. Opus defaults to 1M context, which is included with Max\u002FTeam\u002FEnterprise subscriptions at no extra cost. Note: there is a [known upstream bug](https:\u002F\u002Fgithub.com\u002Fanthropics\u002Fclaude-code\u002Fissues\u002F39841) where Claude Code incorrectly gates Opus 1M behind Extra Usage on Max — this is Anthropic's to fix.\n\n**Why does the health endpoint show `\"plugin\": \"not-configured\"`?**\nYou haven't run `meridian setup`. Without the plugin, OpenCode requests won't have session tracking or subagent model selection. Run `meridian setup` and restart OpenCode.\n\n## Contributing\n\nIssues and PRs welcome. Join the [Discord](https:\u002F\u002Fdiscord.gg\u002FjP2a2Z92NZ) to discuss ideas before opening issues. See [`ARCHITECTURE.md`](ARCHITECTURE.md) for module structure and dependency rules, [`CLAUDE.md`](CLAUDE.md) for coding guidelines, [`E2E.md`](E2E.md) for end-to-end test procedures, and [`MONITORING.md`](MONITORING.md) for understanding token usage and prompt cache health.\n\n## License\n\nMIT\n","Meridian 是一个代理工具，旨在将你的 Claude Max 订阅与 OpenCode、Pi、Droid、Aider、Crush、Cline 等第三方工具连接起来。它通过桥接 Anthropic 的官方 SDK，使这些工具能够使用 Claude Max 的功能，包括会话管理、流式传输和提示缓存。Meridian 完全基于 Claude Code SDK 构建，不涉及任何 OAuth 拦截或二进制修补，确保了安全性和合规性。适用于需要在多种开发环境和终端中集成 Claude AI 功能的场景，尤其适合那些希望利用 Anthropic 提供的强大语言模型来增强现有工作流程的开发者。",2,"2026-06-11 03:51:54","high_star"]