Koog 1.0 idioms, gotchas, and scaffolding skills for Kotlin agents on the JVM
88
88%
Does it follow best practices?
Impact
88%
1.95xAverage score across 43 eval scenarios
Passed
No known issues
Embed and retrieve from a docs corpus as an agent tool
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%
Expose an agent over a Ktor HTTP route
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%
Consume a remote A2A agent as a tool
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%
Install Langfuse exporter via the OpenTelemetry feature
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%
Compress conversation history with TL;DR mid-run
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%
Install Trace feature with edge and node events for local debugging
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%
Attach a user-uploaded image via Attachment.image()
Uses Attachment.image to wrap the file
0%
100%
Constructs a Message.User with attachments
0%
100%
Sends via nodeLLMSendMessage, not nodeLLMRequest
0%
100%
Strategy is typed strategy<File, String>
0%
100%
Returns text from a final nodeFinish edge
0%
100%
PDF and URL image attachments in one agent call
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%
Sub-agent-as-tool via AIAgentService.fromAgent
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%
Construct PlannerAIAgent with Planners.llmBased
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%
Wire an ACP server with cancellation support
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%
0%
Mentions the example or feature module's API
0%
100%
Does not block on coroutine internals
100%
100%
Install the Sql feature with read-only mode and schema scope
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%
100%
Adds the agents-features-sql dependency and JDBC driver
0%
100%
Build a single-block FunctionalAIAgent
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%
Test with TestPromptExecutor.scripted and an event recorder
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%
Configure two LLM providers via Spring Boot autoconfig
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%
Annotated ToolSet for a String-in/String-out function
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%
Custom strategy graph with subgraphWithVerification and fix
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%
cacheControl breakpoint on a long Anthropic system prompt
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%
Stream LLM reply via nodeLLMRequestStreaming
Uses nodeLLMRequestStreaming
100%
100%
Supplies a chunk handler lambda
100%
100%
Names that the handler must not block
33%
100%
Wires the streaming node into a top-level strategy<...>
80%
100%
Does not include tool nodes
100%
100%
Cap token spend with history compression on overrun
Installs the Tokenizer feature
0%
100%
Sets a 50000 runBudget
0%
100%
Picks BudgetAction.CompressHistory
0%
100%
Adds the tokenizer dependencies
0%
100%
Does not lower the model to a cheaper one
0%
100%
Notes how the cap surfaces in observability if installed
0%
0%
Build a prompt DSL with few-shot examples
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%
Install the Persistence feature for planner crash recovery
Installs the Persistence feature
0%
0%
Adds the JDBC persistence backend dependency
0%
0%
Configures the backend with the JDBC connection
0%
0%
Uses Persistence type names, not Persistency
0%
0%
Shows resume path with runFromCheckpoint
0%
0%
Notes serializability requirement for storage
0%
0%
Scaffold a new Koog 1.0 OpenAI project from scratch
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%
Caller-triggered snapshot with runFromSnapshot fork
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%
Redirect from Snapshot to Persistence for automatic crash recovery
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%
Refuse to scaffold over an existing non-empty directory
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%
Redirect from planner to graph DSL when topology is fixed
Names the topology as the disqualifying signal
92%
0%
Redirects to the graph DSL
26%
0%
Does not install agents-planner
100%
100%
Acknowledges the developer's framing without capitulating
80%
0%
Mentions the cost penalty of an unwarranted planner
80%
0%
Redirect from generic Persistence to chat-history for conversation resume
Identifies the three persistence layers in Koog
0%
0%
Routes to chat-history-jdbc
0%
100%
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%
Use responseProcessor for typed JSON output from the agent
Uses responseProcessor on the factory
0%
0%
Parameterizes AIAgent with the typed Output
0%
0%
Reuses the developer's data class verbatim
0%
0%
Drops the regex parsing
0%
0%
Does not introduce a custom strategy
0%
0%
Replace removed AgentMemory with LongTermMemory
Replaces AgentMemory with LongTermMemory
0%
100%
Renames queryExtractor and extractionStrategy
0%
100%
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%
Compose PlannerNode tree with parallel inside sequential
Uses PlannerNode.parallel inside PlannerNode.sequential
0%
40%
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%
Redirect from response cache to Anthropic prompt caching
Names the cache-vs-response distinction
0%
100%
Recommends the provider-side caching path
0%
100%
Does not wrap the executor in an in-process cache
100%
100%
Acknowledges the framing without capitulating
0%
80%
Mentions Anthropic's minimum-token requirement
0%
100%
Scaffold a Koog 1.0 Anthropic project into an empty existing directory
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%
Install JDBC chat-history feature for per-user session resume
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%
Tool<TArgs, TResult> subclass with typed input and output
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%
Decline to apply the subtask-pipeline pattern when the workload is a single text-to-text transform with no phases
Names the absence of distinct phases as the disqualifier
72%
0%
Redirects to the simpler shape
86%
73%
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%
Merge MCP registry with existing local ToolRegistry via +
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%
Build a Koog strategy with a tool-handling loop and conditional branching; produce correct member-vs-extension imports for the DSL primitives
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%
Connect to an SSE-only MCP server; produce correct extension imports for `fromSseUrl` and the `-jvm:1.0.0-beta` dependency line
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%
Wire Streamable HTTP MCP transport to a remote server
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%
Wire stdio MCP transport against a local subprocess
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%
Build a support triage agent with four typed phases, sliced tools, and a verify/adjust loop
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%
60%
Print tool-call trace via handleEvents
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%
Table of Contents