Files
autoreg-skills-max/skills/lobehub-pool/references/lobehub-cli-reverse.md

5.1 KiB

LobeHub CLI Reverse Engineering (2026-07-02)

Discovery

LobeHub has a CLI (@lobehub/cli, binary lh) that provides a REAL API to LobeHub Cloud. This disproves the prior claim that "LobeHub = UI frontend, NOT API."

Source

  • GitHub: lobehub/lobehub monorepo
  • CLI code: apps/cli/src/
  • Server routers: apps/server/src/routers/lambda/aiChat.ts (tRPC)
  • Constants: apps/cli/src/constants/urls.ts

Architecture

lh CLI → app.lobehub.com (tRPC server)
       → agent-gateway.lobehub.com (WebSocket streaming)
       → Auth: .lobehub/credentials.json (JWT/OIDC)
  • Server: app.lobehub.com (tRPC protocol)
  • WebSocket gateway: agent-gateway.lobehub.com
  • Auth headers: X-API-Key (API key) or Oidc-Auth (JWT)
  • Credentials stored: ~/.lobehub/credentials.json (encrypted blob)
  • Settings: ~/.lobehub/settings.json

Key Commands

# Auth
lh login                                    # Browser Device Code Flow
lh whoami                                   # Check current user
lh login --server <url>                     # Custom server

# Models
lh provider list                            # List providers (openai, anthropic, deepseek, etc.)
lh model list <providerId>                  # List models for provider
lh model view <id>                          # Model details

# Generation
lh generate text <prompt> [options]         # Text generation (single completion)
lh generate image <prompt>                  # Image generation
lh generate video <prompt>                  # Video generation
lh generate tts <text>                      # Text-to-speech
lh generate asr <audio-file>                # Speech-to-text

# Other
lh agent                                    # Manage agents
lh kb                                       # Knowledge bases
lh session-group                            # Session groups
lh thread                                   # Message threads

lh generate text Options

-m, --model <model>        Model ID (provider/model format) (default: openai/gpt-4o-mini)
-p, --provider <provider>  Provider name (derived from model if omitted)
-s, --system <prompt>      System prompt
--temperature <n>          Temperature (0-2)
--max-tokens <n>           Maximum output tokens
--stream                   Enable streaming (SSE, renders incrementally)
--json                     Output full JSON response
--pipe                     Pipe mode: read additional context from stdin

CRITICAL: Always use --stream --json together

Without --json: plain text output (hard to parse). Without --stream: --json tries to parse the entire response as one JSON object — fails on models that return reasoning tokens (DeepSeek) with: Unexpected token 'i', "id: undefi"... is not valid JSON

With --stream --json: JSON Lines output — each line is either:

  1. A string token (text chunk): "Hello" → json.loads() gives the text
  2. A JSON object (metadata): {"delta":{"role":"assistant"},...}, {"totalTokens":...}, {"duration":...}

Stream Output Format (JSON Lines)

{"delta":{"role":"assistant"},"id":"gate-...","index":0}     # initial delta
"token"                                                       # text chunk (string)
"another"                                                     # more text
{"totalTokens":27,"cost":0,...}                               # usage
{"duration":203,"latency":2585,"tps":29.55,...}               # timing

Status markers to filter out

These appear as string tokens but are NOT text content:

SKIP_TOKENS = {"in_progress", "message_stop", "end_turn", "completed", "done", "max_tokens"}

Available Models (verified 2026-07-02)

OpenAI (via LobeHub)

  • openai/gpt-5.5 (enabled)
  • openai/gpt-5.4 (enabled)
  • openai/gpt-5.4-mini (enabled)
  • openai/gpt-5.5-pro, gpt-5.4-pro, gpt-5.4-nano (disabled by default)
  • openai/o4-mini, o3-pro, o3 (disabled)

Anthropic (via LobeHub)

  • anthropic/claude-fable-5 (enabled)
  • anthropic/claude-opus-4-8 (enabled)
  • anthropic/claude-opus-4-7 (enabled)
  • anthropic/claude-sonnet-4-6 (enabled)
  • anthropic/claude-haiku-4-5 (enabled)
  • anthropic/claude-opus-4-6 (disabled)

DeepSeek (via LobeHub)

  • deepseek/deepseek-v4-pro (enabled)
  • deepseek/deepseek-v4-flash (enabled)
  • deepseek/deepseek-r1 (enabled)

Other providers available

google, glmcodingplan, kimicodingplan, moonshot, bedrock, bailiancodingplan, vertexai, azure, azureai, aihubmix, openrouter, fal, ollama, ollamacloud, vllm

Windows Subprocess Pitfall

asyncio.create_subprocess_exec("lh", ...) fails with FileNotFoundError: [WinError 2]. The lh shim in PATH is a bash script; Windows needs lh.cmd.

Fix: Use full path to lh.cmd:

LH_CMD = r"C:\Users\User\AppData\Roaming\npm\lh.cmd"
proc = await asyncio.create_subprocess_exec(LH_CMD, "generate", "text", ...)

Python Async Generator Pitfall

return value inside an async def generator = SyntaxError: 'return' with value in async generator.

Fix: Use yield for final result instead of return:

async def run_lh(...):
    # ... process tokens ...
    yield {"type": "done", "text": "".join(text_buf), "usage": usage}
    # NO return statement