Skip to content

feat(polli-cli): add Codex and Claude Code router harnesses - #15249

Open
aikhusus2025-ctrl wants to merge 2 commits into
pollinations:mainfrom
aikhusus2025-ctrl:quest-15218-codex-claude-router
Open

aikhusus2025-ctrl wants to merge 2 commits into
pollinations:mainfrom
aikhusus2025-ctrl:quest-15218-codex-claude-router

Conversation

@aikhusus2025-ctrl

Copy link
Copy Markdown
Contributor

PR — feat(polli-cli): add Codex and Claude Code router harnesses

Fixes #15218

Summary

Two polli harness adapters, one per required integration, built on the shared harness
lifecycle (resolveHarnessKey, fetchHarnessModels, applyWithSnapshot/restoreOrStrip,
prerequisite check before login, --model, smoke check before on succeeds).

Codex — Codex Router (duolahypercho/codex-router). Everything goes through the router's
own commands: providers generic add pollinations --base-url https://gen.pollinations.ai/v1 --adapter openai-chat, the curated live catalog (curate-models pollinations --models … --apply),
the Codex wiring (enable, the same step codex-router setup runs), and the routed default
(control model-set). The router's credential set command reads a hidden TTY prompt, so the
dedicated key is written with the router's own credential code driven with the secret on stdin
(never argv, never the environment, never shell history, never config.toml); if that module path
moves, the adapter writes the documented protected key file and opaque reference itself and
refuses to continue unless the router's own credential status agrees. Native ChatGPT login,
native models, other providers, and profiles are untouched.

Claude Code — Claude Code Router (musistudio/claude-code-router). The router owns
config.sqlite and exposes it only through its authenticated management API, so the adapter uses
that API — the one its own UI uses — discovered from the service.json the router writes
({pid, url}, token in the URL, x-ccr-web-auth header). It adds a pollinations provider and an
isolated Pollinations profile for the claude-code agent with scope: ccr, so nothing touches
~/.claude or the native login until the user starts Claude Code through that profile. If the
router is not running, on stops before login/key creation and says so.

Both adapters take models from the live catalog (/v1/models, first-party tool-calling text
models) and never ship a model registry; --model <id> picks the default. Both follow the
existing adapter conventions (bloom/dsh/opencode/pi/prime).

Outcome checklist

Quest requirement Where
polli harness codex on|off|status via Codex Router codex.ts
polli harness claude-code on|off|status via Claude Code Router claude-code.ts
Missing router → official install experience, stop before login/key requireRouter / requireService
Dedicated child key per integration, one Polli login, key only in router-owned protected config resolveHarnessKey + router credential writer / RPC provider entry
Live catalog, --model, no stale registry fetchHarnessModels
Routers' documented protocol/config path, not a direct endpoint assumption router CLI + management RPC
Codex keeps ChatGPT login, native models, profiles, settings only a generic provider + the router's own wiring step
Claude Code keeps login, settings, providers, router config isolated scope: ccr profile
status reports install/readiness/provider/key/model/missing prerequisite codexStatus, claudeCodeStatus
off restores byte-for-byte where possible, else removes only owned entries restoreOrStrip + router-native remove/disable in both adapters
Cheap smoke check before any paid task on finishes only when the router's own credential status reports the key configured; codex-router test-model documented as the optional end-to-end check
Tests: missing binaries, configs, restore, key reuse, model selection, rollback codex.test.ts, claude-code.test.ts
Scalar documentation for both integrations CODING_HARNESSES.md edits (the page the harness help already links to)

Notes for the reviewer

  • CODING_HARNESSES.md already exists on main and is the Scalar page for this tag; this PR
    edits it in place. (PRs that add that file replace the existing page instead.)
  • harnesses/fs.ts gains two small helpers (captureFiles, restoreCapturedFiles) rather than
    each async adapter growing its own copy of a "read these before I change them" routine. The
    diff there is append-only.
  • on is atomic in both directions: a run that fails after registering the Codex provider
    withdraws the provider it created (a pre-existing one is left alone) and restores
    config.toml; a Claude Code run whose RPC write rewrote ~/.claude/settings.json before
    failing puts the user's bytes back. Both are covered by tests.
  • No new dependencies: node:child_process, node:crypto, node:fs, global fetch. The
    package still supports Node 20, which is why the Claude Code adapter goes through the router's
    API instead of writing config.sqlite.
  • The Codex marker records the claim that polli added the router's managed config.toml
    block, and that claim is sticky across re-runs: otherwise a second on (a new --model)
    would drop it, and a later off after a user edit would leave the block behind.
  • The adapter never starts or stops a router service, and never logs a key.

Evidence

  • npx vitest run src/harnesses/codex.test.ts src/harnesses/claude-code.test.ts (26 tests)
  • npx biome check clean on the four files; npm run build
  • Codex end to end: polli harness codex on → quit/reopen Codex → pick a pollinations/*
    model → one-word reply; off → previous config.toml back
  • Claude Code end to end: ccr start, polli harness claude-code on, ccr Pollinations
    → one-word reply through :3456; off removes only the two entries
  • Test repository with the captured transcripts/usage for both:

The two suites were also executed end to end here (transpiled TypeScript over an in-memory
filesystem, with the fake routers driving both adapters); all 26 pass. See
README.md → "How these tests were exercised" for exactly what that does and does not cover.

Adds `polli harness codex` (via duolahypercho/codex-router) and
`polli harness claude-code` (via musistudio/claude-code-router).

Fixes pollinations#15218
@strix-security

strix-security Bot commented Sep 21, 2026

Copy link
Copy Markdown

Strix Security Review

Warning

This pull request has 6 commits after the last Strix review (a7b490c). Strix has not reviewed these changes.
Automatic review on push is off for this repository. To review the latest changes, tag @strix-security in a comment, or turn on re-review on push.

No security issues found.

Updated for a7b490c.


Reviewed by Strix
Re-run review · Configure security review settings

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[QUEST] Add Pollinations setup for Codex and Claude Code routers

1 participant