CtrlK
BlogDocsLog inGet started
Tessl Logo

jbaruch/koog

Koog 1.0 idioms, gotchas, and scaffolding skills for Kotlin agents on the JVM

87

1.85x
Quality

88%

Does it follow best practices?

Impact

87%

1.85x

Average score across 45 eval scenarios

SecuritybySnyk

Advisory

Suggest reviewing before use

Overview
Quality
Evals
Security
Files

Evaluation results

100%

5%

Ground an Agent in a Documentation Corpus

Embed and retrieve from a docs corpus as an agent tool

Criteria
Without context
With context

Exposes retrieval as a Tool, not as an augmenter

100%

100%

Builds an embedder from a provider

100%

100%

Builds a vector store and indexes documents

100%

100%

Adds the RAG and embeddings dependencies

66%

100%

Registers the search tool with the agent's ToolRegistry

100%

100%

Search tool returns formatted results, not raw vector hits

100%

100%

100%

72%

Expose a Koog Agent on an HTTP Endpoint

Expose an agent over a Ktor HTTP route

Criteria
Without context
With context

Installs the Koog Ktor plugin

0%

100%

Adds the koog-ktor dependency

0%

100%

Configures the prompt executor inside the install block

20%

100%

Reads the OpenAI API key from the environment

100%

100%

Adds a POST /agent route

100%

100%

Resolves the agent from the plugin attribute

0%

100%

100%

8%

Delegate Heavy Analysis to a Remote Agent

Consume a remote A2A agent as a tool

Criteria
Without context
With context

Uses A2AClient to call the remote

100%

100%

Adds a2a-core and a2a-client dependencies

60%

100%

Wraps the A2A call inside a tool

100%

100%

Reads the bearer token from the environment

100%

100%

Registers the wrapper tool with the agent

100%

100%

100%

Send Agent Traces to Langfuse

Install Langfuse exporter via the OpenTelemetry feature

Criteria
Without context
With context

Adds the agents-features-opentelemetry dependency

100%

100%

Installs OpenTelemetry in the trailing lambda

100%

100%

Calls addLangfuseExporter inside the install block

100%

100%

Sets langfuse.session.id from the environment

100%

100%

Turns on verbose mode

100%

100%

Does not stack a second backend integration

100%

100%

100%

5%

Compress History Between Phases of a Long Run

Compress conversation history with TL;DR mid-run

Criteria
Without context
With context

Calls replaceHistoryWithTLDR inside llm.writeSession

85%

100%

Compresses only at the boundary node, not every node

100%

100%

Picks WholeHistory or equivalent TL;DR strategy

100%

100%

Does not introduce LongTermMemory

100%

100%

Compression happens before the next LLM call in drafting

100%

100%

100%

74%

Find Out Why an Agent Is Stuck in a Loop

Install Trace feature with edge and node events for local debugging

Criteria
Without context
With context

Installs the Trace feature

0%

100%

Adds the agents-features-trace dependency

0%

100%

Captures EDGE_EVALUATION events

40%

100%

Captures NODE_ENTRY events

53%

100%

Sends trace to a local sink

80%

100%

0%

Send a User-Uploaded Screenshot to the Agent

Attach a user-uploaded image via Attachment.image()

Criteria
Without context
With context

Uses Attachment.image to wrap the file

0%

0%

Constructs a Message.User with attachments

0%

0%

Sends via nodeLLMSendMessage, not nodeLLMRequest

0%

0%

Strategy is typed strategy<File, String>

0%

0%

Returns text from a final nodeFinish edge

0%

0%

100%

29%

Contract and Product Image Analyzer

PDF and URL image attachments in one agent call

Criteria
Without context
With context

PDF via Attachment.file

40%

100%

Image via Attachment.image(url)

80%

100%

Anthropic model with PDF support

100%

100%

No manual file encoding

100%

100%

Both attachments in one Message.User

100%

100%

Runtime attachment construction in node body

20%

100%

Sends via nodeLLMSendMessage

0%

100%

100%

63%

Wrap a Smaller Agent as a Tool for a Bigger One

Sub-agent-as-tool via AIAgentService.fromAgent

Criteria
Without context
With context

Uses AIAgentService.fromAgent to wrap the find agent

0%

100%

Calls createAgentTool with typed input/output

0%

100%

Provides agentDescription and inputDescription for the LLM

66%

100%

Preserves the find agent's separate configuration

100%

100%

Registers the wrapped tool in the main agent's ToolRegistry

46%

100%

Does not introduce a strategy graph or subgraph

100%

100%

20%

-5%

Build a Triage Agent Whose Steps Depend on Findings

Construct PlannerAIAgent with Planners.llmBased

Criteria
Without context
With context

Picks the LLM-based planner primitive

0%

0%

Adds the separate planner module dependency

0%

0%

Passes the planner as the strategy parameter

33%

0%

Sets a much higher maxIterations than the default

0%

0%

Includes the lookup tools in the registry

100%

100%

Uses top-level AIAgent factory

100%

100%

89%

54%

Make a Koog Agent Cancellable from an IDE Plugin

Wire an ACP server with cancellation support

Criteria
Without context
With context

Installs the ACP feature

0%

100%

Adds the agents-features-acp dependency

0%

100%

Makes the long-running tool honor cancellation

93%

100%

Notes that catching CancellationException would defeat cancel

13%

40%

Mentions the example or feature module's API

0%

80%

Does not block on coroutine internals

100%

100%

95%

30%

Let an Analytics Agent Read From the Events Table

Install the Sql feature with read-only mode and schema scope

Criteria
Without context
With context

Installs the Sql feature in read-only mode

20%

100%

Scopes the schema to the named tables

60%

100%

Caps result rows

100%

100%

Reads DB credentials from environment

100%

100%

Pins schema in system prompt

100%

66%

Adds the agents-features-sql dependency and JDBC driver

0%

100%

100%

5%

Build a Minimal Text-Transform Agent

Build a single-block FunctionalAIAgent

Criteria
Without context
With context

Uses the functional-agent factory

85%

100%

Strategy block is a single suspending block

100%

100%

Trims the LLM response inside the block

100%

100%

Includes the system prompt for formal-English rewriting

100%

100%

Reads OPENAI_API_KEY from environment

100%

100%

No tools registered

100%

100%

100%

22%

Write a Deterministic Unit Test for a Koog Agent

Test with TestPromptExecutor.scripted and an event recorder

Criteria
Without context
With context

Adds agents-test as testImplementation

53%

100%

Uses a scripted/mocked prompt executor

90%

100%

Records tool-call sequence via handleEvents

92%

100%

Asserts ordering — lookup_priority before classification

86%

100%

Tools run their real implementations

20%

100%

Single agent.run call per test

100%

100%

100%

73%

Wire a Spring Boot App With Two LLM Providers

Configure two LLM providers via Spring Boot autoconfig

Criteria
Without context
With context

Configures both providers under ai.koog.<provider>

0%

100%

Reads both keys from environment variables

100%

100%

Migrates service code from LLMClient to MultiLLMPromptExecutor

0%

100%

Routes by model at the call site

33%

100%

Does not introduce a custom @Bean LLMClient override

0%

100%

Does not remove the starter dependency

40%

100%

100%

5%

Add a Weather Lookup Function to an Existing Agent

Annotated ToolSet for a String-in/String-out function

Criteria
Without context
With context

Picks the annotated ToolSet style

100%

100%

Annotates parameters with @LLMDescription

100%

100%

Annotates the class and method with @LLMDescription

100%

100%

Registers via ToolRegistry DSL

75%

100%

Passes the registry into AIAgent at construction

100%

100%

Does not introduce typed args classes

100%

100%

100%

30%

Author a Generate → Verify → Fix Strategy

Custom strategy graph with subgraphWithVerification and fix

Criteria
Without context
With context

Uses subgraphWithTask and subgraphWithVerification

40%

100%

Conditional edge from verify drives the loop

100%

100%

Fix loops back to verify

100%

100%

Each subgraph has its own tools set

66%

100%

Verifier uses a cheaper model than fixer

30%

100%

Top-level strategy<Input, Output>(name) declaration

100%

100%

100%

100%

Cache a Long System Prompt for Anthropic Calls

cacheControl breakpoint on a long Anthropic system prompt

Criteria
Without context
With context

Uses cacheControl on the system segment

0%

100%

Mentions Anthropic minimum-token requirement

0%

100%

Places the breakpoint at end of system content

0%

100%

Uses the prompt DSL builder

0%

100%

References observability for cache-hit verification

0%

100%

Does not change the agent's model

0%

100%

0%

-87%

Stream the Agent's Reply to the Caller

Stream LLM reply via nodeLLMRequestStreaming

Criteria
Without context
With context

Uses nodeLLMRequestStreaming

100%

0%

Supplies a chunk handler lambda

100%

0%

Names that the handler must not block

33%

0%

Wires the streaming node into a top-level strategy<...>

80%

0%

Does not include tool nodes

100%

0%

Failed

Cap token spend with history compression on overrun

100%

38%

Build a Prompt With Few-Shot Examples

Build a prompt DSL with few-shot examples

Criteria
Without context
With context

Uses the prompt { ... } DSL builder

16%

100%

System turn names the classification task

100%

100%

Each example is a user/assistant pair

90%

100%

Examples are inline literal strings

100%

100%

Imports prompt builder from ai.koog.prompt.dsl

0%

100%

Does not introduce a PromptAugmenter

100%

100%

80%

80%

Make a Long-Running Planner Agent Survive Restarts

Install the Persistence feature for planner crash recovery

Criteria
Without context
With context

Installs the Persistence feature

0%

100%

Adds the JDBC persistence backend dependency

0%

100%

Configures the backend with the JDBC connection

0%

0%

Uses Persistence type names, not Persistency

0%

100%

Shows resume path with runFromCheckpoint

0%

100%

Notes serializability requirement for storage

0%

100%

100%

85%

Scaffold a New Agent Project from Scratch

Scaffold a new Koog 1.0 OpenAI project from scratch

Criteria
Without context
With context

Uses 1.0+ umbrella coordinate

0%

100%

Targets JDK 17 toolchain

0%

100%

Uses top-level AIAgent factory

0%

100%

Reads API key from environment

66%

100%

Wires simpleOpenAIExecutor and a current OpenAI model

0%

100%

Omits the default singleRunStrategy

0%

100%

Runs the agent inside runBlocking

0%

100%

Initializes git in the new directory

0%

100%

Application plugin wired with mainClass

100%

100%

100%

100%

Fork an Agent Run to Compare Two Strategy Variants

Caller-triggered snapshot with runFromSnapshot fork

Criteria
Without context
With context

Installs the Snapshot feature

0%

100%

Adds the agents-features-snapshot dependency

0%

100%

Calls snapshot() at the decision point

0%

100%

Demonstrates two runFromSnapshot calls

0%

100%

Notes serializability requirement

0%

100%

87%

87%

Make a Long-Running Agent Survive Server Restarts

Redirect from Snapshot to Persistence for automatic crash recovery

Criteria
Without context
With context

Distinguishes caller-triggered from continuous save

0%

100%

Routes to the Persistence feature

0%

100%

Does NOT recommend installing the snapshot feature

0%

100%

Acknowledges the developer's word choice without capitulating

0%

70%

Mentions the cost of frequent checkpoints

0%

0%

100%

5%

Scaffold Into a Directory That Already Contains Files

Refuse to scaffold over an existing non-empty directory

Criteria
Without context
With context

Detects the non-empty state before writing

100%

100%

Refuses to proceed without explicit confirmation

100%

100%

Asks an explicit yes/no overwrite question

75%

100%

Names what would be overwritten

100%

100%

Leaves the directory unchanged on refusal

100%

100%

93%

22%

Build a "Planning" Agent for a Fully Known Workflow

Redirect from planner to graph DSL when topology is fixed

Criteria
Without context
With context

Names the topology as the disqualifying signal

92%

100%

Redirects to the graph DSL

26%

100%

Does not install agents-planner

100%

100%

Acknowledges the developer's framing without capitulating

80%

53%

Mentions the cost penalty of an unwarranted planner

80%

100%

66%

31%

Make a Chatbot Remember Conversations Per User

Redirect from generic Persistence to chat-history for conversation resume

Criteria
Without context
With context

Identifies the three persistence layers in Koog

0%

12%

Routes to chat-history-jdbc

0%

93%

Does NOT install the generic Persistence feature

100%

100%

Acknowledges the developer's word choice without capitulating

0%

0%

Does NOT recommend LongTermMemory

100%

100%

65%

65%

Make an Agent Return a Typed Classification

Use responseProcessor for typed JSON output from the agent

Criteria
Without context
With context

Uses responseProcessor on the factory

0%

100%

Parameterizes AIAgent with the typed Output

0%

88%

Reuses the developer's data class verbatim

0%

0%

Drops the regex parsing

0%

0%

Does not introduce a custom strategy

0%

80%

98%

98%

Bump a 0.x Codebase Using AgentMemory to 1.0

Replace removed AgentMemory with LongTermMemory

Criteria
Without context
With context

Replaces AgentMemory with LongTermMemory

0%

100%

Renames queryExtractor and extractionStrategy

0%

86%

Removes IngestionTiming

0%

100%

Drops .invoke from the AIAgent call

0%

100%

Adds the new LongTermMemory dependency

0%

100%

Bumps JDK target to 17

0%

100%

Updates all Koog coordinates to 1.0+

0%

100%

75%

65%

Model a Research Workflow as Parallel Subtasks

Compose PlannerNode tree with parallel inside sequential

Criteria
Without context
With context

Uses PlannerNode.parallel inside PlannerNode.sequential

0%

66%

Builds the agent with PlannerAIAgent / Planners.*

0%

100%

Tracks current subtask via storage key

25%

25%

Adds the planner module dependency

0%

100%

Sets maxIterations well above the default

0%

100%

Does not over-engineer with graph subgraphs

100%

100%

94%

69%

Cut Costs on a Long System Prompt That's Called Hundreds of Times a Day

Redirect from response cache to Anthropic prompt caching

Criteria
Without context
With context

Names the cache-vs-response distinction

0%

92%

Recommends the provider-side caching path

0%

96%

Does not wrap the executor in an in-process cache

100%

100%

Acknowledges the framing without capitulating

0%

70%

Mentions Anthropic's minimum-token requirement

0%

100%

100%

60%

Scaffold an Agent into an Existing Empty Directory with Anthropic

Scaffold a Koog 1.0 Anthropic project into an empty existing directory

Criteria
Without context
With context

Uses simpleAnthropicExecutor

0%

100%

Selects a current Anthropic model

25%

100%

Reads ANTHROPIC_API_KEY from the environment

100%

100%

Accepts the existing-empty-directory state without overwrite

100%

100%

Uses 1.0+ umbrella coordinate

0%

100%

Top-level AIAgent factory call

0%

100%

100%

100%

Returning Users Lose Their Conversation

Install JDBC chat-history feature for per-user session resume

Criteria
Without context
With context

Installs the JDBC chat-history feature

0%

100%

Adds the JDBC chat-history dependency

0%

100%

Reads DB credentials from environment

0%

100%

Threads userId as sessionId on agent.run

0%

100%

Does not require user to thread message history manually

0%

100%

100%

44%

Expose an Account Lookup to the Agent

Tool<TArgs, TResult> subclass with typed input and output

Criteria
Without context
With context

Subclasses Tool<TArgs, TResult>

26%

100%

Declares a ToolDescriptor

100%

100%

Implements suspend execute(args) returning the typed result

25%

100%

Registers with the ToolRegistry DSL

100%

100%

Reuses the existing @Serializable data classes

30%

100%

Does not introduce a ToolSet wrapper

100%

100%

35%

-35%

Build a Quick One-Shot Text Reformatter

Decline to apply the subtask-pipeline pattern when the workload is a single text-to-text transform with no phases

Criteria
Without context
With context

Names the absence of distinct phases as the disqualifier

72%

0%

Redirects to the simpler shape

86%

0%

Does not produce subgraphWithTask code

50%

100%

Does not introduce typed handoff data classes

46%

100%

Engages with the developer's framing without capitulating

90%

0%

100%

10%

Add an MCP Server's Tools Alongside Existing Local Tools

Merge MCP registry with existing local ToolRegistry via +

Criteria
Without context
With context

Composes the two registries with +

100%

100%

Preserves the existing CalculatorTools registration

100%

100%

Uses the modern HTTP MCP transport

100%

100%

Adds the agents-mcp dependency

0%

100%

Constructs the merged registry before AIAgent(...)

100%

100%

Calls the suspending MCP builder inside a coroutine context

100%

100%

100%

82%

Add a Tool-Handling Loop to a Koog Strategy

Build a Koog strategy with a tool-handling loop and conditional branching; produce correct member-vs-extension imports for the DSL primitives

Criteria
Without context
With context

Imports the `onToolCalls` extension explicitly

0%

100%

Imports the `onTextMessage` extension explicitly

0%

100%

Does not invent a member import for `forwardTo`

100%

100%

Uses both edge primitives the loop needs

0%

100%

Chains `nodeExecuteTools` to `nodeLLMSendToolResults` explicitly

0%

100%

Wires the loop back through `nodeExecuteTool` on continued tool calls

0%

100%

100%

72%

Connect a Koog Agent to an Older MCP Server

Connect to an SSE-only MCP server; produce correct extension imports for `fromSseUrl` and the `-jvm:1.0.0-beta` dependency line

Criteria
Without context
With context

Picks the SSE transport

27%

100%

Imports the `fromSseUrl` extension explicitly

0%

100%

Pins the MCP artifact to `1.0.0-beta`

0%

100%

Uses the `-jvm` suffix on the artifact

0%

100%

Builds the registry before constructing the agent

100%

100%

Calls the suspending builder inside a coroutine context

100%

100%

100%

15%

Connect an Agent to the GitHub MCP Server

Wire Streamable HTTP MCP transport to a remote server

Criteria
Without context
With context

Uses the Streamable HTTP transport

100%

100%

Adds the agents-mcp dependency

25%

100%

Passes the server URL to the transport configuration

100%

100%

Builds the registry before constructing the agent

100%

100%

Calls the suspending builder inside a coroutine context

100%

100%

Reads the GitHub token from the environment

100%

100%

Passes the token as a bearer header in the transport config

100%

100%

100%

15%

Connect an Agent to a Locally Launched Playwright MCP Server

Wire stdio MCP transport against a local subprocess

Criteria
Without context
With context

Uses the process-based MCP transport

83%

100%

Launches the process with ProcessBuilder

100%

100%

Adds the agents-mcp dependency

50%

100%

Builds the registry before constructing the agent

100%

100%

Calls the suspending builder inside a coroutine context

100%

100%

Does not import Ktor or HTTP-client types

100%

100%

100%

45%

Build a Customer-Support Agent for a Bank

Build a support triage agent with four typed phases, sliced tools, and a verify/adjust loop

Criteria
Without context
With context

Tools sliced into communication / read / write ToolSets

64%

100%

Each phase grants only the matching tool subset

53%

100%

Typed @LLMDescription'd data classes for inter-phase handoffs

32%

100%

Uses subgraphWithTask<In, Out> for each phase

86%

100%

Verification + adjust loop with CriticResult branching

60%

100%

Mixed model selection per phase

60%

100%

Declares the required Gradle dependencies

20%

100%

100%

95%

See What the Agent Is Doing During a Demo

Print tool-call trace via handleEvents

Criteria
Without context
With context

Installs the event-handler feature

0%

100%

Adds the agents-features-event-handler dependency

0%

100%

Subscribes to onToolCallStarting

0%

100%

Subscribes to onToolCallFinished

0%

100%

Uses distinct visual markers for start vs end

0%

100%

Does not also install OpenTelemetry

100%

100%

100%

60%

Expose a Calendar ToolSet to Other Agents over MCP

Expose an existing ToolSet as a stdio MCP server

Criteria
Without context
With context

Calls startStdioMcpServer

40%

100%

Adds the agents-mcp-server dependency

12%

100%

Wraps the existing ToolSet in a ToolRegistry

40%

100%

Keeps the process alive after startup

46%

100%

Does not reach for the client transport surface

100%

100%

63%

-37%

Remember Which Excuses We've Already Sent

Refuses to use chat-history as a fact store

Criteria
Without context
With context

Names the chat-history-vs-fact-store distinction

100%

0%

Recommends LongTermMemory or a Tool

100%

92%

Does not install JdbcChatHistory / chat-history-jdbc

100%

100%

Does not synthesise pseudo-turns into a custom ChatHistoryProvider

100%

100%

Acknowledges the framing without capitulating

100%

0%

Evaluated
Agent
Claude Code
Model
Claude Sonnet 4.6

Table of Contents

Ground an Agent in a Documentation CorpusExpose a Koog Agent on an HTTP EndpointDelegate Heavy Analysis to a Remote AgentSend Agent Traces to LangfuseCompress History Between Phases of a Long RunFind Out Why an Agent Is Stuck in a LoopSend a User-Uploaded Screenshot to the AgentContract and Product Image AnalyzerWrap a Smaller Agent as a Tool for a Bigger OneBuild a Triage Agent Whose Steps Depend on FindingsMake a Koog Agent Cancellable from an IDE PluginLet an Analytics Agent Read From the Events TableBuild a Minimal Text-Transform AgentWrite a Deterministic Unit Test for a Koog AgentWire a Spring Boot App With Two LLM ProvidersAdd a Weather Lookup Function to an Existing AgentAuthor a Generate → Verify → Fix StrategyCache a Long System Prompt for Anthropic CallsStream the Agent's Reply to the CallerBuild a Prompt With Few-Shot ExamplesMake a Long-Running Planner Agent Survive RestartsScaffold a New Agent Project from ScratchFork an Agent Run to Compare Two Strategy VariantsMake a Long-Running Agent Survive Server RestartsScaffold Into a Directory That Already Contains FilesBuild a "Planning" Agent for a Fully Known WorkflowMake a Chatbot Remember Conversations Per UserMake an Agent Return a Typed ClassificationBump a 0.x Codebase Using AgentMemory to 1.0Model a Research Workflow as Parallel SubtasksCut Costs on a Long System Prompt That's Called Hundreds of Times a DayScaffold an Agent into an Existing Empty Directory with AnthropicReturning Users Lose Their ConversationExpose an Account Lookup to the AgentBuild a Quick One-Shot Text ReformatterAdd an MCP Server's Tools Alongside Existing Local ToolsAdd a Tool-Handling Loop to a Koog StrategyConnect a Koog Agent to an Older MCP ServerConnect an Agent to the GitHub MCP ServerConnect an Agent to a Locally Launched Playwright MCP ServerBuild a Customer-Support Agent for a BankSee What the Agent Is Doing During a DemoExpose a Calendar ToolSet to Other Agents over MCPRemember Which Excuses We've Already Sent