@rynfar/meridian 1.51.0 → 1.53.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -99,7 +99,7 @@ Then in `~/.config/opencode/opencode.json`:
99
99
 
100
100
  > **Important:** Do not use `meridian setup` on NixOS. It writes an absolute Nix store path (e.g. `/nix/store/...-meridian-1.x.x/lib/...`) 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.
101
101
 
102
- > **Note:** The bundled Claude Code binary (`claude.exe`) is patched with `autoPatchelfHook` at build time, so it runs on NixOS out of the box. If you previously enabled `programs.nix-ld.enable = true` as a workaround for `Could not start dynamically linked executable` (#501), that is no longer required for Meridian.
102
+ > **Note:** Meridian's package depends on the unfree `claude-code` from nixpkgs instead of bundling its own binary. The flake accepts the unfree license when it builds the package and exports the finished derivation, so consuming it through the overlay or `packages.<system>.meridian` does not re-run nixpkgs' unfree check and needs no `allowUnfree` setting.
103
103
 
104
104
  **Home Manager service** -- run Meridian as a user systemd service:
105
105
 
@@ -121,6 +121,10 @@ Then in `~/.config/opencode/opencode.json`:
121
121
  # passthrough = true;
122
122
  # defaultAgent = "opencode";
123
123
  # sonnetModel = "sonnet";
124
+ # Load plugins from the Nix store (rendered to a plugins.json manifest).
125
+ # The official scrub plugins ship prebuilt via the meridian overlay:
126
+ # pluginConfig = [ { path = pkgs.meridianPlugins.opencode-scrub.path; } ];
127
+ # pluginDir = "/path/to/extra/plugins";
124
128
  };
125
129
  # Extra env vars not covered by settings
126
130
  # environment = {
@@ -493,6 +497,30 @@ ANTHROPIC_API_KEY=x ANTHROPIC_BASE_URL=http://127.0.0.1:3456 \
493
497
 
494
498
  > **Note:** `--no-stream` is incompatible due to a litellm parsing issue — use the default streaming mode.
495
499
 
500
+ ### Codex CLI
501
+
502
+ Codex CLI ≥ 0.96 dropped `wire_api = "chat"` and speaks only the OpenAI **Responses API** (`/v1/responses`), which Meridian serves. Add a provider to `~/.codex/config.toml`:
503
+
504
+ ```toml
505
+ model = "claude-sonnet-5"
506
+ model_provider = "meridian"
507
+
508
+ [model_providers.meridian]
509
+ name = "Meridian"
510
+ base_url = "http://127.0.0.1:3456/v1"
511
+ wire_api = "responses"
512
+ env_key = "MERIDIAN_KEY" # any value unless MERIDIAN_API_KEY is set
513
+ ```
514
+
515
+ ```bash
516
+ MERIDIAN_KEY=x codex "refactor this function"
517
+ MERIDIAN_KEY=x codex exec "run the tests and summarize failures" # non-interactive
518
+ ```
519
+
520
+ Codex is a tool-driving agent — Meridian runs the `/v1/responses` endpoint in **passthrough** mode automatically (Codex executes its own shell/apply-patch tools), so no `MERIDIAN_PASSTHROUGH` change is needed. A harmless `Model metadata for 'claude-sonnet-5' not found` warning from Codex is expected — it doesn't recognize non-OpenAI model ids but works regardless.
521
+
522
+ `model_reasoning_effort` is supported and won't stall the CLI, but Claude's private thinking isn't yet carried **across** turns — the Responses API's encrypted-reasoning envelope is OpenAI-specific and incompatible with Claude's signed thinking blocks, so cross-turn reasoning continuity is deferred (each turn still reasons with full context including tool results). Verified on Codex 0.144 with plain, tool-driving, and reasoning-enabled turns.
523
+
496
524
  ### OpenAI-compatible tools (Open WebUI, Continue, etc.)
497
525
 
498
526
  Meridian speaks the OpenAI protocol natively — no LiteLLM or translation proxy needed.
@@ -660,6 +688,7 @@ export ANTHROPIC_BASE_URL=http://127.0.0.1:3456
660
688
  | [Pi](https://github.com/mariozechner/pi-coding-agent) | ✅ Verified | models.json config (see above) — full tool support via passthrough; detected via `x-meridian-agent: pi` header |
661
689
  | [Claude Code](https://docs.anthropic.com/en/docs/claude-code) | ✅ Verified | `ANTHROPIC_BASE_URL` — remote clients share a Max subscription over the network; client CWD preserved in system prompt |
662
690
  | [Cherry Studio](https://github.com/CherryHQ/cherry-studio) | ✅ Verified | `cherry` adapter (see above) — chat client with Claude's built-in web search via internal mode |
691
+ | [Codex CLI](https://github.com/openai/codex) | ✅ Verified | `/v1/responses` (see above) — Responses-API provider, passthrough tool execution; verified on 0.144 (plain + tool-driving turns) |
663
692
  | [Continue](https://github.com/continuedev/continue) | 🔲 Untested | OpenAI-compatible endpoints should work — set `apiBase` to `http://127.0.0.1:3456` |
664
693
 
665
694
  Tested an agent or built a plugin? [Open an issue](https://github.com/rynfar/meridian/issues) and we'll add it.
@@ -680,12 +709,14 @@ src/proxy/
680
709
  │ ├── cherry.ts ← Cherry Studio adapter (internal mode + web search)
681
710
  │ ├── claudecode.ts ← Claude Code adapter (remote clients sharing a Max host)
682
711
  │ ├── openai.ts ← OpenAI-endpoint adapter (/v1/chat/completions)
712
+ │ ├── codex.ts ← Codex CLI adapter (/v1/responses, forced passthrough)
683
713
  │ └── passthrough.ts ← LiteLLM passthrough adapter
684
714
  ├── query.ts ← SDK query options builder
685
715
  ├── errors.ts ← Error classification
686
716
  ├── models.ts ← Model mapping (sonnet/opus/haiku, agentMode)
687
717
  ├── tokenRefresh.ts ← Cross-platform OAuth token refresh
688
718
  ├── openai.ts ← OpenAI ↔ Anthropic format translation (pure)
719
+ ├── openaiResponses.ts ← OpenAI Responses API ↔ Anthropic translation (pure)
689
720
  ├── setup.ts ← OpenCode plugin configuration
690
721
  ├── session/
691
722
  │ ├── lineage.ts ← Per-message hashing, mutation classification (pure)
@@ -788,6 +819,8 @@ ANTHROPIC_API_KEY=your-secret-key ANTHROPIC_BASE_URL=http://meridian-host:3456 o
788
819
  | `MERIDIAN_SESSION_DIR` | `CLAUDE_PROXY_SESSION_DIR` | `~/.cache/meridian` | Directory for the persisted session store |
789
820
  | `MERIDIAN_DEBUG` | `CLAUDE_PROXY_DEBUG` | unset | Set to `1` for verbose request/session logging |
790
821
  | `MERIDIAN_SILENT` | `CLAUDE_PROXY_SILENT` | unset | Set to `1` to suppress startup output (used by embedding plugins) |
822
+ | `MERIDIAN_PLUGIN_DIR` | — | `~/.config/meridian/plugins` | Plugin auto-discovery directory |
823
+ | `MERIDIAN_PLUGIN_CONFIG` | — | `~/.config/meridian/plugins.json` | Plugin manifest path |
791
824
 
792
825
  †Sonnet 1M requires Extra Usage on all plans including Max ([docs](https://code.claude.com/docs/en/model-config#extended-context)). Opus 1M is included with Max/Team/Enterprise at no extra cost.
793
826
 
@@ -799,6 +832,7 @@ ANTHROPIC_API_KEY=your-secret-key ANTHROPIC_BASE_URL=http://meridian-host:3456 o
799
832
  | `POST /v1/messages` | Anthropic Messages API |
800
833
  | `POST /messages` | Alias for `/v1/messages` |
801
834
  | `POST /v1/chat/completions` | OpenAI-compatible chat completions |
835
+ | `POST /v1/responses` | OpenAI Responses API (Codex CLI ≥ 0.96) |
802
836
  | `GET /v1/models` | OpenAI-compatible model list |
803
837
  | `GET /health` | Auth status, mode, plugin status |
804
838
  | `POST /auth/refresh` | Manually refresh the OAuth token |
@@ -862,7 +896,9 @@ opt-in plugins instead:
862
896
  | [`@rynfar/meridian-plugin-pi-scrub`](https://github.com/rynfar/meridian-plugin-pi-scrub) | Strips Pi's coding-agent-harness prompt line that Anthropic meters as Extra Usage. |
863
897
  | [`@rynfar/meridian-plugin-opencode-scrub`](https://github.com/rynfar/meridian-plugin-opencode-scrub) | Strips OpenCode harness boilerplate from the system prompt before it reaches Claude. |
864
898
 
865
- Install into Meridian's config dir and register the built file in
899
+ **Nix users:** the flake packages all three prebuilt — `pkgs.meridianPlugins.<name>` via the `meridian` overlay (or `meridian.legacyPackages.${system}.meridianPlugins`), each exposing `.path` for a `plugins.json` entry or the home-manager `pluginConfig` option. Pins are refreshed by a scheduled workflow that rebuilds every plugin before bumping.
900
+
901
+ Everyone else: install into Meridian's config dir and register the built file in
866
902
  `~/.config/meridian/plugins.json`:
867
903
 
868
904
  ```bash
@@ -880,6 +916,8 @@ npm install @rynfar/meridian-plugin-hermes-scrub
880
916
 
881
917
  Paths must be absolute — the loader does not expand `~`.
882
918
 
919
+ Both plugin locations are configurable for the standalone CLI: `MERIDIAN_PLUGIN_DIR` overrides the auto-discovery directory and `MERIDIAN_PLUGIN_CONFIG` the manifest path (useful for Nix, containers, or running several instances with different plugin sets).
920
+
883
921
  ## CLI Commands
884
922
 
885
923
  | Command | Description |
@@ -925,6 +963,8 @@ docker run -v ~/.claude:/home/claude/.claude -p 3456:3456 meridian
925
963
 
926
964
  Meridian refreshes OAuth tokens automatically — once the credentials are mounted, no further browser access is needed.
927
965
 
966
+ > **macOS hosts:** mounting `~/.claude` does **not** carry credentials into the container — on macOS the CLI stores OAuth tokens in the Keychain, not in files, so the container sees an empty credential store and requests fail with an authentication error. Use an [OAuth-token profile](#oauth-token-profiles-in-docker-no-volume-mount) instead (recommended), or run `claude login` once inside the container (`docker exec -it <name> claude login`).
967
+
928
968
  ### Multiple profiles in Docker
929
969
 
930
970
  Authenticate each profile locally, then pass them to Docker via the `MERIDIAN_PROFILES` environment variable:
@@ -992,20 +1032,13 @@ meridian refresh-token
992
1032
  curl -X POST http://127.0.0.1:3456/auth/refresh
993
1033
  ```
994
1034
 
995
- **I'm getting `400 You're out of extra usage` only when tools are present. What do I do?**
996
- First confirm the failure pattern: a tiny no-tool request succeeds, but the same client fails once it sends tool definitions. If that is the case, beta-header stripping and model fallback usually will not help because the request body still contains agentic tool context.
997
-
998
- For the affected adapter, try disabling the connecting client's system prompt while keeping the Claude Code prompt enabled:
999
-
1000
- ```bash
1001
- curl -X PATCH http://127.0.0.1:3456/settings/api/features/pi \
1002
- -H 'Content-Type: application/json' \
1003
- -d '{"clientSystemPrompt":false,"codeSystemPrompt":true}'
1004
- ```
1035
+ **I'm getting `400 You're out of extra usage` on tool-bearing requests. What do I do?**
1036
+ This error class ([#516](https://github.com/rynfar/meridian/issues/516), historical) came from Anthropic's server-side classifier gating certain requests behind Extra Usage. It had two distinct triggers, both now addressed:
1005
1037
 
1006
- Replace `pi` with the adapter you use (`opencode`, `crush`, `forgecode`, `droid`, `passthrough`, or `openai`). You can make the same change in the `/settings` UI under **SDK Feature Toggles**. (The `openai` adapter used by the `/v1/chat/completions` endpoint — already defaults `codeSystemPrompt` to off, so on that one you typically only need `clientSystemPrompt:false`.)
1038
+ - **Harness fingerprints** identity lines in a client's system prompt (e.g. pi's "coding agent harness" line) were metered as Extra Usage. The [official scrub plugins](#official-plugins) strip these and remain recommended for the affected harnesses.
1039
+ - **Tool-definition presence** — reported in mid-2026 as triggering independently of prompt content; as of July 2026 this no longer reproduces on Max accounts (verified with Extra Usage disabled, tools present, and an unscrubbed fingerprint prompt). It appears to have been resolved upstream in Anthropic's billing policy.
1007
1040
 
1008
- This keeps the SDK's preset prompt and tool bridge, but removes the external client's large agent prompt from the request. That may help when the error is triggered by the combination of tool definitions plus client prompt context. The tradeoff is that the connected agent may behave more like vanilla Claude Code because its own persona and workflow instructions are no longer included. If it still fails, the remaining options are to use fewer/no tools for that client, enable Extra Usage/API billing, or switch to a local/provider-backed model for that workflow. See [#516](https://github.com/rynfar/meridian/issues/516) for the current debugging thread.
1041
+ If you still hit the error on a current release, first check `GET /v1/usage/quota` to rule out genuinely exhausted quota, then try disabling the connecting client's system prompt for the affected adapter while keeping the Claude Code prompt enabled (in the `/settings` UI under **SDK Feature Toggles**, or `PATCH /settings/api/features/<adapter>` with `{"clientSystemPrompt":false,"codeSystemPrompt":true}`) and please report it on [#516](https://github.com/rynfar/meridian/issues/516) with your plan type, since remaining occurrences are likely account-cohort specific (Team plans are treated differently by the API).
1009
1042
 
1010
1043
  **I'm hitting rate limits on 1M context. What do I do?**
1011
1044
  Meridian 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://code.claude.com/docs/en/model-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/Team/Enterprise subscriptions at no extra cost. Note: there is a [known upstream bug](https://github.com/anthropics/claude-code/issues/39841) where Claude Code incorrectly gates Opus 1M behind Extra Usage on Max — this is Anthropic's to fix.