Install
Two paths. Pick whichever you already have.
Standalone — no app required
curl -fsSL https://lingcode.dev/install-cli.sh | sh
Downloads a signed, notarized tarball to ~/.lingcode/cli/ and symlinks it to ~/.local/bin/lingcode. The bundled Node bridge ships inside, so the Claude provider works without LingCode.app installed (you still need Node.js and an API key).
From an installed LingCode.app
/Applications/LingCode.app/Contents/Resources/bin/lingcode install
The install subcommand tries /usr/local/bin first, falls back to ~/.local/bin, prints a PATH hint if needed.
Quickstart
# One command to store a key in the Keychain (opens browser)
lingcode auth login
# Interactive session (Claude by default)
lingcode
# Interactive session with another provider
lingcode --provider ollama --model llama3.2
lingcode --provider groq --model llama-3.1-70b-versatile
# One-shot
lingcode ask "explain this error" < build.log
echo "what's 2+2?" | lingcode ask -
# Check your setup
lingcode auth status
lingcode --help
Interactive REPL
lingcode with no arguments drops you into an interactive multi-turn session. It's the same as lingcode repl, just shorter to type.
The REPL has two flavors depending on provider:
- Claude mode — full agentic loop: tool use, file edits, MCP servers, hooks, session resumption, permission prompts, colored diffs. Runs via the bundled Node bridge +
@anthropic-ai/claude-agent-sdk. - OpenAI-compatible mode — text-only streaming chat with any OpenAI-compatible endpoint. No tool use, but works against OpenAI, Groq, Together, OpenRouter, Mistral, xAI, Fireworks, Ollama, DeepSeek, and custom proxies.
Input editor
When stdin is a TTY, you get a proper line editor:
↑ / ↓ | Recall previous / next input |
← / → / Home / End | Cursor movement |
Tab | Complete slash commands (builtin + custom) |
Trailing \ | Continue the input on the next line |
Ctrl-C | Cancel running query (Claude) / abort line |
Ctrl-D | Exit on empty line, otherwise delete character |
| Bracket-paste | Paste multi-line clipboard content as one input |
Prompt
The REPL prompt shows turn count and cumulative cost once they're non-zero:
lingcode> explain this repo
…
lingcode [1t $0.003]> now suggest a refactor
…
lingcode [2t $0.011]>
Providers
Pick with --provider; override model, base URL, or API key env var as needed.
| Provider | Env var | Default model | Tools? |
|---|---|---|---|
claude (default) | ANTHROPIC_API_KEY | SDK default | ✓ |
deepseek | DEEPSEEK_API_KEY | deepseek-chat | — |
openai | OPENAI_API_KEY | gpt-4o-mini | — |
groq | GROQ_API_KEY | llama-3.1-70b-versatile | — |
together | TOGETHER_API_KEY | Llama-3.3-70B-Instruct-Turbo | — |
openrouter | OPENROUTER_API_KEY | anthropic/claude-sonnet-4 | — |
mistral | MISTRAL_API_KEY | mistral-large-latest | — |
xai | XAI_API_KEY | grok-2-latest | — |
fireworks | FIREWORKS_API_KEY | llama-v3p1-70b-instruct | — |
ollama | — (none) | llama3.2 | — |
deepseek-compat | DEEPSEEK_API_KEY | deepseek-chat | — |
Any OpenAI-compatible endpoint
lingcode --provider openai \
--base-url https://my-proxy.example.com/v1 \
--api-key-env MY_KEY_VAR \
--model gpt-4o
Tool use, MCP, hooks, and session resumption are Claude-only — those features depend on the Agent SDK. Everything else in the REPL (slash commands, markdown rendering, token display, history, tab completion) works across all providers.
One-shot ask
# Simple
lingcode ask "summarise this repo's architecture"
# Pipe content in
cat error.log | lingcode ask "explain this"
# Read the entire prompt from stdin
echo "what is 2+2?" | lingcode ask -
# Switch provider
lingcode ask --provider groq "quick: what does this regex do? /\d{3}-\d{4}/"
# Claude with full tool use, auto-approved
lingcode ask --provider claude --yolo "add a .gitignore entry for .DS_Store"
# Attach a file
lingcode ask --provider claude --file screenshot.png "what's wrong in this UI?"
# Structured output (good for scripts)
lingcode ask --output-format stream-json "fix the failing test in main.swift"
Useful flags
--continue | Resume the most recent Claude session in this directory |
--resume <id> | Resume a specific session by ID |
--file <path> | Attach a file (image, PDF, text). Repeatable. Claude only. |
--allowed-tools Read,Write | Allow only these tools (Claude only) |
--disallowed-tools Bash | Disallow these tools |
--add-dir ~/other | Extra directory the agent can touch. Repeatable. |
--thinking | Enable Claude's extended thinking |
--system-prompt "..." | Override the system prompt |
--append-system-prompt "..." | Append to the system prompt |
--output-format text|json|stream-json | Output shape |
--output path/out.md | Write the response to a file |
--verbose | Don't truncate tool input/output |
--yolo | Auto-allow every tool call. Dangerous. |
Slash commands
Type these at the REPL prompt.
All providers
/help | List commands |
/model <name> | Switch model mid-session |
/reset | Clear conversation (Claude: also starts a fresh session) |
/cost | Cumulative token usage |
/export [path] | Save transcript as markdown |
/clear | Clear screen |
/quit | Exit |
Claude-only
/mode <mode> | Change permission mode (default / acceptEdits / plan / dontAsk / bypassPermissions) |
/yolo | Bypass all permission prompts |
/compact | Summarise and compress conversation history |
/session | Show current session ID |
/tools | List available built-in tools |
/commands | List custom slash commands |
/doctor | Diagnose environment (node, API key, bridge, MCP, hooks) |
/init | Generate CLAUDE.md for the current project |
OpenAI-compatible only
/system <text> | Replace the system prompt for this session |
Custom
Put a Markdown file at .claude/commands/<name>.md and invoke it as /project:<name>. Files at ~/.claude/commands/ are invoked as /user:<name>. Bare /<name> checks project first, then user. Any text after the command name is appended to the body.
$ echo "Explain the changes staged in git in plain English." > .claude/commands/explain-staged.md
$ lingcode
lingcode> /project:explain-staged
Auth & API keys
Three sources, checked in this order: environment variable, macOS Keychain, config file. Any one is enough.
# Browser-assisted: opens the provider console, prompts for the key, stores in Keychain
lingcode auth login
lingcode auth login --provider deepseek
# Direct
lingcode auth set anthropic sk-ant-...
lingcode auth set deepseek sk-...
# See what's configured (values masked)
lingcode auth status
# Remove a key
lingcode auth delete anthropic
About OAuth: Anthropic does not issue OAuth client IDs to third-party CLIs, so a true /login OAuth flow is not possible. lingcode auth login is the practical replacement — it opens the console in your browser, waits for you to paste the key, and stores it.
Other providers (openai, groq, together, openrouter, mistral, xai, fireworks, ollama) don't use the Keychain path — just set their environment variable in your shell:
export OPENAI_API_KEY=sk-...
export GROQ_API_KEY=gsk-...
MCP servers, hooks, custom commands
Compatible with Claude Code's project conventions.
MCP servers
Put a .mcp.json at the project root (or ~/.claude.json globally):
{
"mcpServers": {
"filesystem": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "."]
}
}
}
Override with --mcp-config <path>. Disable with --no-mcp. MCP is Claude-only.
Hooks
Put hooks in .claude/settings.json. They run as shell commands with CLAUDE_TOOL_NAME, CLAUDE_TOOL_INPUT, and (for PostToolUse) CLAUDE_TOOL_RESULT in the environment:
{
"hooks": {
"PreToolUse": [
{ "matcher": "Write|Edit", "hooks": [{ "type": "command", "command": "echo about to edit: $CLAUDE_TOOL_INPUT" }] }
],
"Stop": [
{ "hooks": [{ "type": "command", "command": "say done" }] }
]
}
}
Custom slash commands
Markdown files under .claude/commands/ (project) or ~/.claude/commands/ (user). Same format as Claude Code — the file body is the prompt.
Talking to the running app
When LingCode.app is open, these commands drive it over a Unix socket at ~/Library/Application Support/LingCode/ipc.sock:
| Command | What it does |
|---|---|
lingcode ping | Check whether the app is running and responsive. |
lingcode open path/to/file.swift | Open a file or folder in the app (launches it if needed). |
lingcode status | Focused project and any active agent runs. |
lingcode ask "..." | Route the prompt through the app; stream its answer to stdout. |
lingcode watch | Tail agent activity in real time. Ctrl-C to stop. |
Pass --headless to ask to force local execution even with the app open.
Subcommand reference
| Subcommand | Purpose |
|---|---|
repl (default) | Interactive multi-turn session. lingcode with no args. |
ask | One-shot prompt; supports streaming, JSON output, attachments, resume. |
auth | login / set / get / delete / status against the macOS Keychain. |
config | Read or write ~/.lingcode/config.json — defaults, stored keys. |
init | Generate a CLAUDE.md for the current project by analysing the repo. |
history | List past sessions from ~/.lingcode/history.jsonl. |
completion zsh|bash|fish | Print a shell completion script. |
ping | IPC probe for the running app. |
open | Open file or folder in the running app. |
status | App focus / agent status. |
watch | Stream live agent activity. |
install | Symlink lingcode onto your PATH. |
Troubleshooting
lingcode: ANTHROPIC_API_KEY is not set
Fix with lingcode auth login, or export in your shell, or run lingcode config set anthropic-api-key sk-ant-....
lingcode: <PROVIDER_API_KEY> is not set
OpenAI-compatible providers use plain env vars. For custom names: lingcode --provider openai --api-key-env MY_KEY.
lingcode: couldn't find Claude agent bridge
The Claude provider needs bridge.mjs, which ships inside LingCode.app or the standalone CLI tarball. Either install LingCode.app at /Applications, or point at a dev copy with export LINGCODE_AGENT_BRIDGE_DIR=/path/to/agent-bridge.
lingcode: cannot find `node` on PATH
Install Node.js (nodejs.org), reopen your shell, then retry. Or set NODE to an explicit path. Only needed for the Claude provider; OpenAI-compatible providers use pure Swift.
Rate-limited / 429 / overloaded
Both ask and repl retry automatically with exponential backoff (up to 5 attempts, up to 60s apart). You'll see rate limited (attempt N/5) — retrying in Xs… on stderr.
The app responds, but I wanted headless
lingcode ask routes through the app by default when it's open. Pass --headless to force local execution.
I pasted an API key into my terminal
Rotate it at the provider's dashboard. Anything in your shell history or tmux scrollback should be treated as leaked. Prefer lingcode auth login (browser paste) or lingcode auth set <provider> <key> — neither writes the key to stdout.