Skip to content

Repository files navigation

cli2openai

简体中文 · English

Use an authenticated Claude Code or Codex CLI as a local OpenAI-compatible translation backend for pdf2zh, then produce translated, bilingual, and left/right paper PDFs. No separate OpenAI-compatible API key is required. An optional Zotero 7+ plugin, PaperBridge, runs the same pipeline locally or over SSH.

Architecture

Independent community software. It is not affiliated with Anthropic, OpenAI, pdf2zh, or Zotero. You are responsible for complying with the terms and usage limits of the CLI provider you use.

Local academic PDF translation

Why this project

  • Reuses a locally authenticated official CLI instead of storing another translation API key.
  • Isolates Claude Code from the user's CLAUDE.md, memory, hooks, and plugins.
  • Replaces the coding-agent system prompt with a concise academic-translation prompt.
  • Removes pdf2zh's verbose client instruction wrapper before each CLI call and rejects any translated prompt text that still appears in a segment or assembled PDF.
  • Rejects translated PDFs before they can be translated a second time.
  • Detects reasoning/tool leakage, unexpected Japanese kana in Chinese output, unsupported semantic anomalies, and missing placeholders or citations; failed segments are retried from source.
  • Keeps italic prose and bold headings out of pdf2zh's formula placeholders, then audits the assembled PDF for high-confidence untranslated fragments before publishing any result paths.
  • Repairs residual figure captions and rotated outer-margin labels, and removes stale link boxes from translated and side-by-side layouts.
  • Normalizes invalid scientific-notation operands emitted in some figure streams, so strict PDF readers preserve the intended transforms without parser warnings.
  • Versions the pdf2zh cache with the prompt policy, so prompt upgrades cannot reuse old translations.
  • Separates cache namespaces by CLI backend and selected model, so switching from Claude to Codex cannot silently reuse the other backend's translation.
  • Automatically restarts a stale shim when shim.py changes.
  • Pins the isolated Codex translation backend to gpt-5.5 with high reasoning effort and gives each Codex segment a bounded 600-second window.
  • Runs CLI calls without session persistence and serializes OAuth refresh at expiry to prevent concurrent workers from corrupting the shared credential file.
  • Runs remote PaperBridge translations as detached server jobs with SSH keepalive and polling, so a dropped long-lived SSH channel cannot kill the translation before download. A server-side hard limit finishes before the client polling deadline and cleans partial status files.

Architecture

PDF -> pdf2zh -> OpenAI-compatible localhost shim -> claude -p / codex exec
                                                       |
                                               deterministic quality gate
                                                       |
                         translated PDF + dual PDF + left/right side-by-side PDF

run.sh is the single production entrypoint used by the shell wrapper and PaperBridge. Its stdout contains only SIDEBYSIDE=, DUAL=, and MONO= paths; progress goes to stderr.

Requirements

  • Linux or WSL (macOS should work when lsof, Bash, and Poppler-compatible tooling are available).
  • Python 3.10+ and either uv or venv/pip.
  • An installed and authenticated Claude Code or Codex CLI.
  • curl; remote PaperBridge hosts also need GNU timeout (normally provided by coreutils); zip is required only to build the Zotero plugin.

Install

git clone https://github.com/myheart521/cli2openai.git
cd cli2openai
chmod +x install.sh run.sh translate.sh scripts/build-paperbridge.sh
./install.sh

Verify your chosen backend independently:

claude -p --model fable "Return exactly OK."
# or
codex exec "Return exactly OK."

Claude model names use aliases such as fable, opus, and sonnet, or full IDs such as claude-fable-5. fable5 is not a valid CLI model name.

Translate a paper

./translate.sh /path/to/paper.pdf
./translate.sh /path/to/paper.pdf zh claude 2
CLI2OPENAI_MODEL=sonnet ./translate.sh /path/to/paper.pdf zh claude 2

Outputs are written under out/:

  • paper-sidebyside.pdf: translated page on the left, original page on the right;
  • paper-dual.pdf: pdf2zh bilingual layout;
  • paper-mono.pdf: translated-only layout.

The default Claude model is fable; override it with CLI2OPENAI_MODEL. Keep concurrency at 2 unless you know the provider limit. Set CLI2OPENAI_IGNORE_CACHE=1 for a forced fresh translation. PDF2ZH_VFONT can override the conservative math-font regex for a paper with unusual formula fonts. SHIM_CALL_TIMEOUT controls the per-segment CLI limit (default: Claude 300 seconds, Codex 600); CAPTION_REPAIR_TIMEOUT defaults to 30 seconds longer than that limit. Codex calls are fixed to gpt-5.5 with a one-run model_reasoning_effort="high" override. These choices do not modify the user's Codex configuration. If Claude authentication is missing or expired, run.sh fails before pdf2zh starts and asks you to run claude auth login.

The pre-flight guard exits with code 3 when the first pages already contain substantial target language text or known contamination signatures. Select the original paper, not a generated PDF.

Run only the OpenAI-compatible shim

python3 shim.py --backend claude --model fable --port 8765 --max-concurrency 2
curl http://127.0.0.1:8765/healthz

Point a client at http://127.0.0.1:8765/v1 with any non-empty dummy API key. The request's model field is intentionally ignored; operators select the real CLI model with --model or CLI2OPENAI_MODEL for Claude, while the Codex backend remains fixed to gpt-5.5.

Do not expose the shim to a network. It has no authentication and launches local CLI processes.

Zotero PaperBridge

Build the plugin:

make plugin
# dist/paperbridge.xpi

In Zotero 7+, open Tools -> Plugins -> gear icon -> Install Plugin From File, then choose the XPI. PaperBridge can:

  • run run.sh on the local computer; or
  • upload the source PDF with SCP, invoke run.sh over SSH, and download the outputs.

Remote hosts, usernames, key paths, and output paths are user preferences and are never bundled in the XPI. Generated attachments are tagged [PaperBridge]; selecting one as input is rejected, which prevents translation-of-a-translation loops. Attaching outputs back to Zotero is off by default.

See the plugin guide for platform-specific configuration. Installed copies can use Tools -> Plugins -> gear icon -> Check for Updates because the XPI contains the repository's version-feed URL.

Quality policy and limitations

The quality gate is deliberately conservative: it blocks high-confidence corruption and retries the source segment, but it cannot prove that every technical statement is translated perfectly. Review critical claims against the original. Complex figures, vertical text, unusual embedded fonts, and scanned PDFs remain subject to pdf2zh layout limitations. The generated side-by-side PDF keeps the original page beside the translation for verification.

Changing the prompt, filter, or quality policy requires bumping PROMPT_VERSION in shim.py; this creates a clean cache namespace. Do not patch pdf2zh's SQLite cache manually.

Privacy and security

The repository intentionally excludes papers, job folders, outputs, logs, local environments, credentials, private keys, hosts, and personal paths. Claude authentication is linked at runtime into the ignored .claude-clean/ directory. Read SECURITY.md before publishing a fork.

Development

make test
make plugin

Every observed leak or marker corruption should become a synthetic regression test. Do not commit real paper segments or user transcripts as fixtures.

License

MIT. Third-party tools and CLIs retain their own licenses and terms.

About

Local Claude Code/Codex CLI bridge for quality-gated bilingual academic PDF translation and Zotero PaperBridge.

Topics

Resources

Contributing

Security policy

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages