Files
Tashfeen 36eea7bba5 cli: publish freellmapi to npm (#671) (#672)
* cli: publish freellmapi to npm (#671)

The README and docs/clients.md have documented `npx freellmapi setup-claude`
since the CLI workspace landed, but the package was never pushed to the
registry — every documented command failed with npm E404.

The CLI itself is fine; only the release path was missing. This adds it:

- cli-release.yml publishes on pushes to main that touch cli/**, guarded by a
  registry version check so ordinary source changes are a no-op and only a
  version bump ships. workflow_dispatch covers the first publish. Publishes
  with --provenance so the tarball is traceable to this repo and commit.
- The workflow installs the packed tarball and runs the binary before
  publishing, which catches a `files` array that drops a runtime import —
  something the unit tests cannot see.
- cli/README.md and cli/LICENSE: the package shipped neither, so the npm page
  would have been blank for a package we ask people to npx. Both are added to
  `files`, along with homepage/bugs/keywords.
- The documented setup command omitted the credential and exited with "No API
  key supplied", so README and docs/clients.md now show --api-key and the
  FREELLMAPI_API_KEY alternative.

Publishing needs an NPM_TOKEN repository secret; the workflow fails with an
explicit message when it is absent rather than erroring inside npm publish.

* cli-release: skip instead of failing when NPM_TOKEN is absent

As written, merging this workflow would have put a red X on main: the push
trigger fires, 0.3.0 is unpublished, and the token check exits 1. The secret
cannot be added until the npm account is available, so the first consequence of
landing the fix would have been a broken main.

An automatic run now warns and skips. A manual run still fails loudly, since
explicitly asking for a publish and silently getting none is worse than an
error. The step summary says which case it hit.

* cli-release: use trusted publishing (OIDC) instead of NPM_TOKEN

npm revoked every classic token in December 2025, so the "classic automation
token" this workflow was written around no longer exists. The replacement,
granular access tokens, default to enforcing 2FA on write and the "bypass 2FA"
escape hatch is being wound down through 2026 — it loses sensitive management
actions this August and direct publish around January 2027. A token-based
workflow would have been deprecated before its first run.

Trusted publishing mints a short-lived OIDC credential per job, so there is no
long-lived secret in the repository at all, and npm attaches provenance without
being asked. Node moves to 24 because OIDC needs npm >= 11.5.1 / Node >=
22.14.0; that is still inside the repo's engines range.

Trusted publishing cannot bootstrap a package that does not exist — npm has no
package settings page to configure a publisher against until a first version
exists — so 0.3.0 is published by hand and every later version goes through
this workflow. The npmjs.com setup is documented in the header.

* cli: drop the leading ./ from the bin path

Publishing 0.3.0 warned:

  npm warn publish "bin[freellmapi]" script name dist/index.js was invalid and removed

The wording is alarming but benign — npm normalises "./dist/index.js" to
"dist/index.js" and publishes the corrected form, so 0.3.0 on the registry does
have a working bin. Writing it normalised keeps the warning out of future
releases and stops the next person having to verify the registry to find out
whether the binary survived.
2026-07-30 02:19:32 -07:00

7.4 KiB

Clients & coding agents

← Back to README · Documentation index

OpenAI-compatible clients

Any client that can target an OpenAI-compatible base URL can use FreeLLMAPI:

  • LangChain, LlamaIndex, official OpenAI SDKs: set base_url to http://localhost:3001/v1 and use the unified key from the dashboard.
  • Local GPU boxes: add custom OpenAI-compatible endpoints for Ollama, llama.cpp, LM Studio, vLLM, or an internal gateway.

Coding agents

Use the generator instead of hand-editing a client configuration:

export FREELLMAPI_API_KEY=<unified-key>   # or pass --api-key on each command
npx freellmapi setup-claude --url http://localhost:3001 --dry-run
npx freellmapi setup-claude --url http://localhost:3001

--dry-run prints a diff. Real writes merge with the existing configuration and create a timestamped backup first. --profile <name> creates a named Claude/Codex profile. The live /v1/models catalog supplies the model ids and context windows.

Agent Automated command Manual base URL Wire
Claude Code setup-claude or credential-free-on-disk launch http://localhost:3001 Anthropic Messages
Codex CLI setup-codex or launch-codex http://localhost:3001/v1 Responses (wire_api = "responses")
Cline setup-cline http://localhost:3001/v1 OpenAI Chat
Continue setup-continue http://localhost:3001/v1 OpenAI Chat / legacy Completions
Aider setup-aider http://localhost:3001/v1 OpenAI Chat
OpenCode setup-opencode http://localhost:3001/v1 OpenAI Chat
Goose setup-goose http://localhost:3001/v1 OpenAI Chat
Qwen Code setup-qwen http://localhost:3001/v1 OpenAI Chat (native Gemini also works)
Roo Code setup-roo http://localhost:3001/v1 OpenAI Chat
Kilo Code setup-kilo http://localhost:3001/v1 OpenAI Chat
Crush setup-crush http://localhost:3001/v1 OpenAI Chat
Cursor setup-cursor prints the guide public https://…/v1 OpenAI Chat
Anything else setup-generic prints a ready block http://localhost:3001/v1 OpenAI Chat

The root-vs-/v1 distinction matters: Claude Code expects the server root because it appends the Anthropic Messages path. OpenAI-compatible clients in this table—including Cline, Aider, Goose, Codex, Continue, OpenCode, Qwen, Roo, Kilo, and Crush—expect their configured base URL to include /v1.

Native Gemini clients

Gemini CLI and Gemini-lineage clients can speak Google's wire format directly:

export GOOGLE_GEMINI_BASE_URL=http://localhost:3001
export GEMINI_API_KEY=freellmapi-your-unified-key
gemini

The native surface implements GET /v1beta/models, model metadata, generateContent, streamGenerateContent (including ?alt=sse), and countTokens. Authentication accepts x-goog-api-key, Bearer, or Gemini's ?key= fallback. Prefer the header: query credentials leak into history and proxy logs.

The Keys → Agents tab maps Gemini Pro, Flash, and Flash-Lite family names to Auto or a pinned catalog model.

Ollama clients

Ollama emulation is off by default. Enable one of these modes on Keys → Agents:

  • open-loopback: no key on this machine only. The socket peer must be 127.0.0.1/::1; enabling desktop LAN access does not widen it. Docker note: inside a container the socket peer is the Docker bridge IP, not loopback, so this mode refuses even host-local traffic through a published port — use key-required for Docker deployments.
  • key-required: clients must send Authorization: Bearer <unified-key>.

The exact endpoints are /api/tags, /api/chat, /api/generate, /api/show, /api/version, /api/embed, and legacy /api/embeddings. Streaming uses newline-delimited JSON, not SSE. Point Zed, JetBrains AI Assistant, or another Ollama-capable client at http://localhost:3001.

Headerless clients

If a client cannot set headers, create a separately revocable token on Keys → Agents and use:

http://localhost:3001/v1/t/<token>/chat/completions
http://localhost:3001/v1/t/<token>/responses
http://localhost:3001/v1/t/<token>/models

The same prefix exposes /api/chat and /api/tags. Never put the unified API key in a URL. URL tokens have independent hashes and immediate revocation because URLs routinely leak into shell history, reverse-proxy logs, and telemetry.

MCP server

On top of inference, the router is an MCP server: agents can introspect it mid-session (usable models and the params each one honors, provider health, usage and cache stats, routing strategy). For Claude Code:

claude mcp add --transport http freellmapi http://localhost:3001/mcp \
  --header "Authorization: Bearer freellmapi-your-unified-key"

Any MCP client that speaks Streamable HTTP works the same way: point it at /mcp with the unified key as a Bearer token.

FreeLLMAPI is local-first and single-user by design. Your provider keys stay in your SQLite database, encrypted at rest, and requests go from your machine to the upstream providers you enabled.

VS Code ghost-text autocomplete (Continue)

FreeLLMAPI exposes /v1/completions for editor autocomplete clients that send legacy OpenAI prompt/suffix requests. Example Continue config:

models:
  - name: FreeLLMAPI Autocomplete
    provider: openai
    model: auto
    apiBase: http://localhost:3001/v1
    apiKey: freellmapi-your-unified-key
    useLegacyCompletionsEndpoint: true
    roles:
      - autocomplete

Context Handoff

When FreeLLMAPI falls over to a different model mid-conversation (quota, rate limit, cooldown), the new model has no idea it is picking up someone else's task. Context handoff adds a single compact system message to the outbound request that tells the new model exactly that:

FreeLLMAPI context handoff:
You are taking over an ongoing conversation from another model (groq:llama-3 → google:gemini-flash).
Continue the user's task using the conversation context already provided in this request.
Do not restart the task, re-ask already answered setup questions, or discard prior tool results.
Respect the user's latest message as the highest-priority instruction.

Recent session summary:
User: …
Assistant: …

Enable it in .env:

FREELLMAPI_CONTEXT_HANDOFF=on_model_switch

How it works:

  • Messages per session are stored in memory (TTL: 3 hours).
  • Only injected when the selected model changes for a given session key.
  • Not injected on the first request, on same-model continuations, or if a handoff message is already present.
  • Session key: X-Session-Id header if present, otherwise SHA-1 of the first user message (same as sticky sessions).
  • Storage is in-memory only. Nothing is written to disk or logged.

Important: Context Handoff improves continuity for conversations routed through FreeLLMAPI. It cannot recover provider-internal hidden state or messages that were never sent to the proxy.