* fix: prevent duplicate connector launches during doctor/connect Mark connectors as starting before the hub daemon spawns so autostart skips in-flight instances, and improve doctor process filtering with container-aware namespace/cgroup checks plus detached log rotation. * Update apps/cli/src/connectors/common.ts Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> * feat(hub): supervise connector processes * feat(connectors): enable tools by default, and stop replaying the Slack greeting Tools were on by default only for Telegram (via --no-tools); Slack, Discord, Linear, Google Chat and WhatsApp all required an explicit --enable-tools. All six now default to tools on and opt out with --no-tools. --enable-tools still parses everywhere, including Telegram which never accepted it, so deployed scripts, systemd units and persisted autostart arguments keep working. Passing both resolves to the safer answer: --no-tools wins. This also affects hub/webview starts, which never emitted a tools flag and so ran those five connectors with tools off. Slack no longer posts the "Connected to Cline." first-contact message. It was gated on per-thread welcomeSentAt, so a connector restart or a cleared history made the next user message look like first contact and replayed the greeting. The host mechanism is unchanged and the other adapters still greet. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(connectors): recover a thread whose session is wedged mid-run A connector thread keeps a long-lived mapping to a hub session. When that session's runtime still had a run in flight and no abort had been requested, every message in the thread came back as "SessionRuntime.shutdown called while a run is in progress" instead of an answer, and stayed that way until someone cleared the binding by hand. Observed on the Cline Mom Slack bot after a stack restart. The connector host already recovers from a session the hub no longer knows about: it forgets the mapping and replays the turn once against a fresh session. This widens the trigger from "session not found" to "session cannot serve another turn" via isUnusableSessionError, so a wedged runtime takes the same path. The shutdown error now carries a stable code (SessionRunInProgressError, session_run_in_progress) so callers can recognise it structurally. The predicate also matches on message, because an error reaching a connector has crossed the hub's JSON boundary and arrives as a bare message - and because a host commonly runs a hub and CLI of different versions. Ordinary run failures still propagate untouched: replacing the session on those would hide real errors and drop the conversation. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(connectors): serialise turns that share a session Answering "what happens if I message the bot in another thread while it is still replying": channel threads were already independent, but DMs were not. findBindingForThread deliberately reuses one binding — and therefore one runtime session — for every message in a DM channel, so a DM stays one continuous conversation. The turn queue, though, was keyed by thread id, and a DM thread id carries the message timestamp. Two messages in flight in the same DM therefore got two independent queues and ran concurrently against a single session, which fails with "shutdown called while a run is in progress" or interleaves two conversations in one session history. The queue key now follows the same identity rule as the binding lookup, via resolveThreadTurnQueueKey next to findBindingForThread so the two cannot drift. DM messages queue behind each other on the shared session; channel threads keep their own key and still run in parallel. Applied to all six adapters, which all had the same mismatch. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(core): abort an in-flight run before tearing its session down Where the Slack bot's "plugin-sandbox process exited (code=null, signal=SIGTERM)" came from, and its "shutdown called while a run is in progress" sibling: both are one event, a session released while a run was still going. stopSession aborts the agent first "so shutdown can proceed", but callers that reach shutdownSession or releaseSessionRuntime another way did not - hub dispose() on a restart being the one that hurt. Without an abort the runtime refuses to shut down, that error is rethrown from the cleanup, and the plugin sandbox is SIGTERMed while tool calls are still pending, so those calls reject with "plugin-sandbox process exited". A connector turn awaiting the run reports whichever surfaced first instead of answering. Both paths now abort and let the run drain before shutting the agent, runtime and sandbox down, guarded on session.aborting so callers that already aborted do not abort twice. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(connectors): stop announcing "Steering current task." Every follow-up sent while the bot was replying added an acknowledgement line to the thread, and the wording overstated what happens: the host treats delivery "steer" the same as "queue", enqueuing the prompt for the session rather than injecting it into the loop already running. The follow-up is now handed over silently. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(core): retire a dead supervised entry before replacing it A start arriving while an instance sat in backoff left the old entry's restart timer live. The timer closes over the old entry object, so when it fired it spawned a second process for the same (channel, instanceId) - untracked by the supervisor's map, so invisible to list() and unreachable by stop() - two connectors holding one bot token, which is the exact failure supervision exists to prevent. Its exit handler then kept reaping the live instance's state and rescheduling restarts. The same window exists before the timer is even scheduled: the exit-cleanup chain runs first, and a replacement made mid-chain would be followed by a restart scheduled for the retired entry. start() now retires a dead existing entry explicitly - cancel its timer, mark it stopped, drop its exit listener. Both the timer callback and the cleanup chain already stand down on "stopped", so one mark covers both phases. * fix(core): serialise supervisor start/stop and wait for stopped processes to die Found by exercising a hub restart against a live webhook connector: the new hub's boot reconnect restarts the adopted survivor - which suspends inside stop() on the CLI cleanup - while the user's `cline connect` arrives as connector.start. With no per-instance serialisation the two starts interleaved across that suspension and both spawned. The map tracked one process while the other lived on untracked, holding the connector's webhook port; the tracked chain crash-looped on EADDRINUSE through all five attempts and ended state=failed, while the ghost kept running with no way to reach it through list() or stop(). Two changes: - start/stop (and the backoff-restart spawn) now run under a per- instance-key promise queue, so one instance has exactly one lifecycle operation in flight. The exit-cleanup chain also stands down when its entry is no longer the one in the map. - stop() waits for the process to actually die after SIGTERM (bounded, then SIGKILL) instead of returning while it still holds its listen port - the race that turned the double-spawn into a crash loop, and that could burn a backoff cycle on any webhook connector restart. process.kill is now injectable (killProcess), which also stops the test suite from signalling arbitrary real pids like 600 on the host. Verified live: the same kill-hub-then-reconnect sequence now converges to one tracked running process, with the concurrent user start correctly answered "already running under the hub". --------- Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Saoud Rizwan <7799382+saoudrizwan@users.noreply.github.com>
Cline CLI
Run Cline in your terminal. Interactive chat for paired sessions, or fully headless for CI/CD and scripting. The CLI shares its agent core with the Cline VS Code extension, JetBrains plugin, and SDK, so plan/act modes, MCP servers, checkpoints, rules, skills, and provider configuration all behave the same across surfaces.
Install
npm install -g cline
For nightly builds:
npm install -g cline@nightly
Platform binaries are published for macOS, Linux, and Windows on arm64 and x64. The cline package resolves the correct binary for your platform via optional dependencies, so no Node, Bun, or Zig runtime is required at install time.
Quick start
Run interactively:
cline
Run a single prompt:
cline "Audit this package and propose fixes"
Pipe input:
cat file.txt | cline "Summarize this"
See cline --help for the full flag reference.
Use any provider
Cline supports the same providers as the VS Code extension. You can sign in to Cline directly, use your ChatGPT Subscription through openai-codex, or bring an API key from Anthropic, OpenAI, Google Gemini, OpenRouter, AWS Bedrock, GCP Vertex, Cerebras, Groq, and any OpenAI-compatible endpoint.
cline auth # interactive sign-in
cline auth cline # OAuth sign-in
cline auth --provider anthropic --apikey sk-... --modelid claude-sonnet-4-6
cline auth without a provider opens the interactive auth setup TUI with the same options as the old CLI flow (Sign in with Cline, Sign in with ChatGPT Subscription, Sign in with OCA, or use your own API key).
OAuth-supported providers (cline, openai-codex, oca) do not auto-launch a browser on normal startup. Authenticate explicitly first with cline auth <provider>. For non-interactive runs, if an OAuth provider is selected and no saved credentials are available, cline fails fast with an authentication message instead of launching a hidden browser flow.
Modes
Cline CLI runs in a few different shapes depending on what you need:
- Interactive TUI:
clineorcline -iopens a full terminal UI with plan/act toggle, slash commands, file mentions, and live tool approvals - One-shot:
cline "your prompt"runs a single turn and exits - JSON:
cline --json "..."streams NDJSON events for piping into other tools - Yolo:
cline --yolo "..."skips approval prompts and exits when the turn finishes - Zen:
cline --zen "..."fires the task to the background hub daemon and exits immediately (see below)
Headless mode for CI/CD
Run Cline with zero interaction for scripting and automation. Pipe input, get JSON output, chain commands, integrate into CI/CD pipelines.
# One-shot prompt, auto-approve all tools
cline --yolo "Run tests and fix any failures"
# Pipe a diff in for review
git diff origin/main | cline "Review these changes for issues"
# NDJSON output for downstream tooling
cline --json "List all TODO comments" | jq -r 'select(.type == "agent_event" and .event.text) | .event.text'
Features
- Streaming TUI built on OpenTUI with markdown rendering, syntax-highlighted diffs, scrollable chat, and mouse support
- Plan/Act mode toggle for switching between planning and execution
- Native MCP support for connecting custom tools
- Checkpoints with
/undoto rewind workspace state - Sub-agent spawning and agent teams for parallel work
- OAuth login for Cline, ChatGPT Subscription (
openai-codex), and OCA - Configurable thinking budgets per run
- Cron and event-driven schedules for recurring agent work
- Chat connectors for Telegram, Google Chat, and WhatsApp
Usage
# Start Cline CLI without a prompt to enter interactive mode
cline
# Single prompt (one-shot) - includes tools, spawn, and teams
cline "Audit this package and propose fixes"
# Interactive mode with a starting prompt
cline -i "Let's work on this together. First, analyze the current state."
# With a custom system prompt
cline -i -s "You are a pirate" "Tell me about the sea"
# Require approval before each tool call
cline --auto-approve false "Inspect and modify this repository"
# Explicit yolo: enables submit_and_exit and disables spawn/team tools by default
cline --yolo --retries 5 "Refactor this package"
# Override consecutive internal mistake (retry) limit (default: 3)
cline --retries 5 "Fix failing tests"
# Team workflow with persistent name
cline --team-name my-team "Plan, implement, and verify release checklist"
cline --team-name my-team "Continue yesterday's team workflow"
# Show verbose run stats (elapsed time, tokens, estimated cost when available)
cline -v "Explain quantum computing"
# Use a specific provider, model, and access token for a single prompt
cline -P openrouter -m google/gemini-3-pro -k sk-... "Set up a storybook"
# Use a different model with the last used provider
cline -m anthropic/claude-opus-4-6 "Explain string theory"
# Stream structured NDJSON output
cline --json "Summarize this repository"
# Quick provider setup
cline auth --provider anthropic --apikey sk-... --modelid claude-sonnet-4-6
cline auth --provider openai-native --apikey sk-... --modelid gpt-5 --baseurl https://api.example.com/v1
MCP servers
Manage MCP servers with the interactive wizard:
cline mcp
cline config mcp
Open the add-server wizard with the name, transport, and command or URL already filled in with cline mcp install (cline mcp add also works). Stdio servers use everything after -- as the command and arguments:
cline mcp install fs -- npx -y @modelcontextprotocol/server-filesystem /tmp
Remote HTTP and SSE servers take a name, transport, and URL. The wizard still asks for auth details before saving:
cline mcp install ctx7 --transport http https://mcp.context7.com/mcp
cline mcp install events --transport sse https://example.com/sse
Because this command opens the wizard, it requires a TTY.
Connectors
Bridge a chat surface into RPC-backed Cline sessions. Each conversation thread maps to a session with full context. Supported platforms: Telegram, Slack, Google Chat, WhatsApp, and Linear.
# Telegram (polling mode)
cline connect telegram -k 123456:ABCDEF...
# Slack (webhook mode)
cline connect slack --bot-token $SLACK_BOT_TOKEN --signing-secret $SLACK_SIGNING_SECRET --base-url https://your-domain.com
# Slack (socket mode)
cline connect slack --bot-token $SLACK_BOT_TOKEN --app-token $SLACK_APP_TOKEN
# Google Chat (webhook mode)
cline connect gchat --base-url https://your-domain.com
# WhatsApp (webhook mode)
cline connect whatsapp --base-url https://your-domain.com
# Linear (webhook mode)
cline connect linear --api-key $LINEAR_API_KEY --base-url https://your-domain.com
# Stop connector bridges and delete their sessions
cline connect --stop
cline connect --stop telegram
In chat surfaces, connector slash commands include /help, /start, /new, /clear, /whereami, /tools, /yolo, /cwd <path>, /schedule, /abort, and /exit. Run cline connect <adapter> --help to see the full flag list for any adapter.
Schedules
Schedule agents on cron-like intervals or external events.
cline schedule create "Daily code review" \
--cron "0 9 * * MON-FRI" \
--prompt "Review PRs opened yesterday and summarize issues." \
--workspace /path/to/repo \
--provider cline \
--model openai/gpt-5.3-codex \
--timeout 3600 \
--tags automation,review
cline schedule list
cline schedule get <schedule-id>
cline schedule trigger <schedule-id>
cline schedule history <schedule-id> --limit 20
cline schedule export <schedule-id> > daily-review.yaml
cline schedule import ./daily-review.yaml
Schedules can route results back to chat surfaces with --delivery-adapter, --delivery-bot, and --delivery-thread.
Options
| Flag | Description |
|---|---|
-s, --system <prompt> |
Override the system prompt |
-P, --provider <id> |
Provider id (default: cline) |
-m, --model <id> |
Model id (default: anthropic/claude-sonnet-4.6) |
-k, --key <api-key> |
API key override for this run |
-p, --plan |
Run in plan mode (default is act mode) |
-i, --tui |
Interactive TUI multi-turn mode |
-t, --timeout <seconds> |
Optional run timeout in seconds |
-c, --cwd <path> |
Working directory for tools |
--config <path> |
Configuration directory (used for CLI home resolution) |
--hooks-dir <path> |
Additional hooks directory hint for runtime hook injection |
--acp |
ACP (Agent Client Protocol) mode |
--thinking [none|low|medium|high|xhigh] |
Model thinking level when supported. Defaults to medium when the flag is provided without a level; thinking is off when the flag is omitted. |
--compaction <agentic|basic|off> |
Context compaction mode. Defaults to agentic; use basic for local truncation or off to disable. |
--retries <count> |
Maximum consecutive mistakes (retries) before halting (default: 3) |
--json |
Output NDJSON instead of styled text |
--data-dir <path> |
Use isolated local state at <path> instead of ~/.cline/data (enables sandbox mode automatically) |
--auto-approve [true|false] |
Set tool auto-approval for all tools |
--kanban |
Run the external kanban app |
-y, --yolo |
Skip tool approval prompts, enable submit_and_exit, and disable spawn/team tools by default |
-z, --zen |
Dispatch the task to the background hub and exit the CLI immediately |
--team-name <name> |
Override the runtime team state name |
-h, --help |
Show help and exit |
-v, --verbose |
Show verbose runtime diagnostics |
-V, --version |
Show version and exit |
--json is non-interactive and requires either a prompt argument or piped stdin. --key takes precedence over environment variables.
Top-level commands
cline config- Open the interactive config viewcline history|h [options]- List session history or manage saved sessionscline version- Show CLI versioncline update [options]- Check for CLI and kanban updatescline auth <provider>- Authenticate or seed provider credentialscline connect <adapter>- Run a chat connector bridge (telegram,gchat,whatsapp)cline connect --stop [adapter]- Stop connector bridge processes and their sessionscline schedule <command>- Create and manage scheduled runscline doctor- Inspect local CLI health and stale processescline doctor fix- Kill stale local RPC listeners and old CLI processescline doctor log- Open the CLI runtime log filecline hook- Handle a hook payload from stdincline hub- Manage the local hub daemoncline kanban- Run the externalkanbanapp, installing it first when needed
Zen mode
--zen (alias -z) runs a task in the background hub daemon and exits the CLI immediately. It is intended for long-running tasks you want to fire off and walk away from.
cline --zen "Refactor the authentication module and add unit tests"
Behavior:
- The CLI starts (or reuses) the local hub daemon, submits the task, then exits. It does not stream output or stay attached to the session.
- Because there is no human in the loop once the CLI exits, zen sessions run with full tool auto-approval (same semantics as
--yolo).spawn/teamtools are disabled by default for safety, consistent with yolo-mode defaults. - If the Cline menubar app is running, it subscribes to hub
ui.notifyevents and will surface a system notification when the task completes. - If the menubar app is not running, there is no live UI for the task. Use
cline historylater to find the session and inspect the result. --zenis incompatible with--data-dir(the implicit sandbox requires a local backend that exits with the CLI) and with--tui(there is no terminal UI to render into).
Tool approval
Tool calls are auto-approved by default. Use --auto-approve false to require review before tool execution.
cline --auto-approve false "Inspect and modify this repository"
When approval is required, the CLI prompts in TTY mode:
Approve tool "<tool_name>" with input <preview>? [y/N]
- Enter
yoryesto approve. - Enter anything else (or press Enter) to reject.
- If stdin/stdout is not a TTY, required-approval calls are denied in terminal mode.
Desktop-integrated approval mode is also supported via env wiring (CLINE_TOOL_APPROVAL_MODE=desktop and CLINE_TOOL_APPROVAL_DIR=<path>). In desktop mode, CLI writes a request JSON file and waits for a matching decision JSON file.
Environment variables
ANTHROPIC_API_KEY- API key for AnthropicCLINE_API_KEY- API key for Cline (when using-P cline)OPENAI_API_KEY- API key for OpenAI (when using-P openai)OPENROUTER_API_KEY- API key for OpenRouter (when using-P openrouter)AI_GATEWAY_API_KEY- API key for Vercel AI Gateway (when using-P vercel-ai-gateway)V0_API_KEY- API key for v0 (when using-P v0)CLINE_DATA_DIR- Base data directory for sessions/settings/teams/hooksCLINE_SANDBOX- Set to1to force sandbox modeCLINE_SANDBOX_DATA_DIR- Override sandbox state directoryCLINE_TEAM_DATA_DIR- Override team persistence directoryCLINE_BUILD_ENV- Runtime build mode for SDK-owned subprocess launchesCLINE_DEBUG_HOST- Host for development inspector listeners (default127.0.0.1)CLINE_DEBUG_PORT_BASE- Base inspector port for development child processesCLINE_TOOL_APPROVAL_MODE- Approval mode (desktopuses file IPC; unset uses terminal prompt)CLINE_TOOL_APPROVAL_DIR- Directory for desktop approval request/decision filesCLINE_LOG_ENABLED- Set to0/falseto disable runtime file loggingCLINE_LOG_LEVEL- Runtime log level (trace|debug|info|warn|error|fatal|silent, defaultinfo)CLINE_LOG_PATH- Runtime log file path (default<CLINE_DATA_DIR>/logs/cline.log)CLINE_LOG_NAME- Logger name embedded in runtime log recordsCLINE_DEBUG- Set to1/trueto print wrapper diagnostics (e.g. the CA bundle summary)
--key takes precedence over environment variables.
Certificate trust
The CLI automatically trusts your operating system's certificate store, so it
works behind corporate TLS-inspecting proxies and with self-signed/internal
endpoints without any setup. On launch the cline wrapper harvests the OS trust
anchors and writes them to ~/.cline/cli-node-extra-ca-certs.pem, then points
the runtime's NODE_EXTRA_CA_CERTS at that bundle. The file is regenerated when
it changes and is safe to delete (it is rebuilt on the next run).
If you set NODE_EXTRA_CA_CERTS yourself, your certificates are merged into
that bundle alongside the system store rather than replacing it. Run with
CLINE_DEBUG=1 to see how many OS and user CAs were loaded and where the bundle
was written.
Contributing
See DEVELOPMENT.md for local development setup, monorepo structure, and TUI architecture. See DISTRIBUTION.md for how the CLI is packaged and distributed.