* core: trigger compaction on the provider's actual input-token count Compaction's trigger compared a character-based estimate (~3 chars/token) against the model's input budget. Dense content -- disassembly, image dumps, minified sources -- tokenizes far denser than that, so a transcript could reach the real context ceiling while the estimate stayed under the threshold and compaction never fired. Affected runs then filled the window and had their turns squeezed down to a handful of output tokens. The runtime now records the provider-reported input-token count for each request and threads it to the prepare-turn pipeline as previousRequestInputTokens; the trigger uses max(estimate, actual), so real usage crosses the threshold even when the estimate does not. The estimate is kept as a floor so the very first oversized turn is still caught before any usage has been reported. Also raises the default summarizer output budget from 4096 to 8192: a model that reasons by default can spend a tight budget on thinking and return no summary text, which skips compaction entirely. * core: forward previous request input tokens through the runtime bridge SessionRuntime.createRuntimePrepareTurn() rebuilds the prepare-turn context field by field, so previousRequestInputTokens was dropped before reaching the compaction pipeline. Every production core session therefore fell back to the character estimate alone and the actual-usage trigger never engaged. Forward the field alongside overflowRecovery and cover the bridge with a regression test. * core: scale the compaction budget by the observed token underestimate The actual-usage trigger only moved the trigger; maxInputTokens still drove the retention target off the unscaled estimate, so a compaction started by real usage could retain too much and overflow again. Divide maxInputTokens by max(1, actual / estimate) instead. The trigger test is algebraically identical to comparing actual usage against the unscaled trigger, while the target, message translation and projection costs now all correspond to the provider's real limit in consistent estimate units. The factor never loosens the budget, engages only on direct evidence of under-counting, and is capped at MAX_INPUT_UNDERESTIMATE_FACTOR so a small estimate cannot collapse it. * core: move the actual-count compaction test off the trigger boundary The provider count was set to exactly the 1.05x multiple used for the budget, which put the scaled trigger within 0.1 token of the estimate; the test only compacted because of ceil rounding. Use 1.5x so it asserts the behavior rather than the rounding. --------- Co-authored-by: Saoud Rizwan <7799382+saoudrizwan@users.noreply.github.com>
The Cline SDK is a TypeScript framework for building AI agents that can edit files, run shell commands, browse the web, call APIs, and use any custom tool you give them. It's the same engine that powers Cline, packaged as a library you can embed in your own applications.
import { Agent } from "@cline/sdk"
const agent = new Agent({
providerId: "cline",
modelId: "openai/gpt-5.5",
systemPrompt: "You are a helpful coding assistant.",
tools: [],
})
const result = await agent.run("Create a REST API with Express and TypeScript")
console.log(result.text)
That's it. The agent streams its response, calls tools if you give it any, and returns when the task is done.
Install
npm install @cline/sdk
SDK Skill
If you use a coding agent (Claude Code, Codex, Cline, etc.), install the Cline SDK skill to give your agent context on the SDK's APIs and best practices to help you build with the Cline SDK.
npx skills add cline/sdk-skill
Prompt it to scaffold agents, create custom tools, wire up plugins, configure providers, and more.
What You Can Build
Coding agents, Slack bots, scheduled automations, code review pipelines, multi-agent teams, IDE integrations -- anything that benefits from an LLM that can take actions, not just generate text.
// Slack bot: each thread gets its own agent with conversation memory
const agents = new Map<string, Agent>()
async function handleMessage(threadId: string, message: string) {
let agent = agents.get(threadId)
if (!agent) {
agent = new Agent({
providerId: "gemini",
modelId: "gemini-3.1-pro-preview",
systemPrompt: "You are a concise Slack assistant.",
tools: [],
})
agents.set(threadId, agent)
}
const result = agent.hasRun
? await agent.continue(message)
: await agent.run(message)
return result.text
}
Explore full working examples in examples/ and app examples in apps/examples/:
| Example | Description |
|---|---|
| Plugins | Custom tools with workspace-aware context, lifecycle hooks, and branch-level safety policies |
| Subagent Orchestration | Spawn and manage background agents with presets, skills, and cross-agent handoffs |
| Hooks | File-based and runtime hooks for logging, review gates, context injection, and lifecycle automation |
| Cron Automations | Recurring and event-driven automation specs for scheduled quality checks and PR workflows |
| Desktop App | Tauri desktop shell with a Bun sidecar backend and Next.js UI |
| VS Code Extension App | VS Code extension example that runs Cline sessions over the RPC runtime |
Custom Tools
Tools are how agents interact with the world. Define a tool with a name, a description the model reads, a JSON Schema for inputs, and a function that does the work:
import { createTool } from "@cline/sdk"
const deploy = createTool({
name: "deploy",
description: "Deploy the app to staging or production.",
inputSchema: {
type: "object",
properties: {
environment: { type: "string", enum: ["staging", "production"] },
},
required: ["environment"],
},
execute: async (input) => {
const result = await runDeployment(input.environment)
return { url: result.url, status: "success" }
},
})
const agent = new Agent({
providerId: "moonshot",
modelId: "kimi-k2.5",
systemPrompt: "You are a deployment assistant.",
tools: [deploy],
})
The agent decides when to call the tool based on the description. It sees the result and incorporates it into its response.
Streaming Events
Every event during execution is observable in real time:
const agent = new Agent({
providerId: "anthropic",
modelId: "claude-opus-4-7",
systemPrompt: "You are a helpful assistant.",
tools: [myTool],
onEvent: (event) => {
switch (event.type) {
case "content_update":
if (event.contentType === "text") process.stdout.write(event.text)
break
case "content_start":
if (event.contentType === "tool") console.log(`\n[${event.toolName}]`)
break
case "usage":
console.log(`\ntokens: ${event.inputTokens} in, ${event.outputTokens} out`)
break
}
},
})
Plugins
Package reusable capabilities as extensions. An extension can register tools, observe lifecycle events, and modify agent behavior:
const metrics: AgentPlugin = {
name: "metrics",
manifest: { capabilities: ["tools", "hooks"] },
setup(api) {
api.registerTool(myCustomTool)
},
hooks: {
beforeRun() {
console.time("agent")
},
beforeTool({ toolCall }) {
console.log(`tool: ${toolCall.toolName}`)
},
afterRun({ result }) {
console.timeEnd("agent")
console.log(`${result.iterations} iterations, ${result.usage.outputTokens} tokens`)
},
},
}
ClineCore: Full Runtime
When you need session persistence, built-in tools, config discovery, and multi-process support, use ClineCore:
import { ClineCore } from "@cline/sdk"
const cline = await ClineCore.create({ clientName: "my-app" })
const session = await cline.start({
prompt: "Set up CI with GitHub Actions",
config: {
providerId: "anthropic",
modelId: "claude-sonnet-4-6",
apiKey: process.env.ANTHROPIC_API_KEY,
cwd: "/path/to/project",
enableTools: true,
},
})
console.log(session.result?.text)
If both cwd and workspaceRoot are omitted, the execution host places the
session in the shared chat workspace at
<cline-data-dir>/workspaces/chat (by default
~/.cline/data/workspaces/chat), seeded with an AGENTS.md rules file that
tells the agent to treat the session as a chat and only create a named
project folder when the user asks for one.
The paths in session.manifest are the authoritative resolved workspace paths.
ClineCore gives the agent built-in tools (bash, editor, read_files, apply_patch, search, fetch_web), persists sessions to SQLite, discovers config from .cline/ directories, and optionally connects to an RPC sidecar for scheduled agents and cross-process session management.
Portable Agent Plugins
ClineCore and Hub-backed SDK clients support Agent Plugins v1 without a client-side loader. The execution host automatically discovers user-installed package directories under ~/.agents/plugins/* on the Hub host. Automatic discovery intentionally does not scan workspace .agents/plugins directories, so opening a repository does not implicitly activate repository-controlled MCP servers. Hosts may explicitly opt in to additional roots through agentPluginPaths; those caller-provided paths are resolved against the session cwd and remain subject to the same package-boundary validation.
Each package is validated from its root plugin.json. Valid immediate-child Agent Skills under skills/ are exposed through the skills tool as plugin-name:skill-name; valid servers from root mcp.json are connected without modifying cline_mcp_settings.json. Invalid packages, components, skills, and MCP entries fail at their specification-defined narrow boundaries.
Agent Plugin discovery is read-only: loading settings validates manifests and inspects skills and mcp.json without starting MCP processes or creating plugin data directories. For stdio MCP servers, the runtime creates the dedicated persistent PLUGIN_DATA directory immediately before launching the server, as required by the Agent Plugins MCP contract.
The Hub also owns Agent Plugin enablement. Hub-backed clients read the same plugin inventory through settings APIs and toggle entries there instead of maintaining client-local state. Disabled plugins are persisted by their validated manifest name and do not contribute skills or MCP servers when a session runtime is built. Every settings mutation publishes settings.changed, so subscribed clients can refresh their settings views.
Agent Plugin contributions are part of a session's runtime snapshot. A client may rebuild an idle session after a toggle (the CLI does this for a toggle made in its interactive settings view), but an already-running turn keeps the tools, skills, and rules it started with. Other existing sessions pick up the new state when they are rebuilt or restarted; new sessions use it immediately. Installing or removing files under ~/.agents/plugins is detected on the next settings refresh or session build rather than pushed by a filesystem watcher.
You can also provide package roots explicitly. Relative paths are resolved by the Hub against the session cwd:
const session = await cline.start({
prompt: "Use the release plugin to prepare this repository",
config: {
providerId: "anthropic",
modelId: "claude-sonnet-4-6",
cwd: "/path/to/project",
enableTools: true,
agentPluginPaths: ["./vendor/release-plugin"],
},
})
Packages
The SDK is a layered stack. Use as much or as little as you need:
| Package | What it does |
|---|---|
@cline/sdk |
Everything you need -- install this one |
@cline/core |
Sessions, persistence, built-in tools, config discovery, RPC |
@cline/agents |
Stateless agent loop with tool execution and streaming |
@cline/llms |
LLM provider gateway (Anthropic, OpenAI, Google, Bedrock, Mistral, and more) |
@cline/shared |
Types, tool creation helpers, hook engine |
@cline/sdk is an alias for @cline/core that re-exports from all packages, so a single install gives you the full API. The individual packages are available if you want a minimal dependency footprint.
CLI
The Cline CLI gives you terminal access to the full SDK:
# Interactive agent
cline
# Single prompt
cline "Refactor the auth module to use JWT"
# Schedule an agent to run daily
cline schedule create "PR summary" --cron "0 9 * * MON-FRI" --prompt "Summarize open PRs"
# Connect a Telegram bot created with @BotFather
cline connect telegram -k "$TELEGRAM_BOT_TOKEN"
# Then send /help or /start to the bot in Telegram
For Telegram-specific connector behavior, see apps/cli/src/connectors/adapters/telegram.md.
Providers
Works with every major LLM provider out of the box:
| Provider | Models |
|---|---|
| Anthropic | Claude Opus 4.7, Sonnet 4.6, Haiku 4.5 |
| OpenAI | GPT-5.5, GPT-5.3 Codex |
| Gemini 3.1 Pro Preview, Gemini 3 Flash Preview | |
| AWS Bedrock | Claude, Llama |
| Mistral | Mistral Large, Codestral |
| Any OpenAI-compatible | vLLM, Together, Fireworks, Groq, etc. |
Documentation
Full documentation at docs.cline.bot/sdk:
- Quickstart -- zero to running agent in 5 minutes
- Core Concepts -- agents, sessions, tools, events, extensions, hooks
- Guides -- end-to-end tutorials for common patterns
- Architecture -- how the SDK is structured and why
- API Reference -- every method, type, and config option
Contributing
To contribute to the project, start with our Contributing Guide to learn the basics. You can also join our Discord to chat with other contributors in the #contributors channel. If you're looking for full-time work, check out our open positions on our careers page!