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
Process steps in order. Do not skip ahead.
implementation("ai.koog:koog-spring-boot-starter:1.0.0")The starter auto-configures one LLMClient bean per enabled provider and one MultiLLMPromptExecutor aggregating them. Adding it transitively pulls the per-provider auto-configurations.
Don't construct executors manually in a @Configuration class when the starter is on the classpath — you'll get two beans and Spring picks one unpredictably.
Proceed immediately to Step 2.
application.ymlEach provider keys off ai.koog.<provider>.api-key and ai.koog.<provider>.enabled. Both must be set for autoconfig to wire the client bean. Provider keys (match the autoconfig class names):
anthropic, deepseek, google, mistralai, ollama, openai, openrouterai:
koog:
google:
api-key: ${GOOGLE_API_KEY}
enabled: true
anthropic:
api-key: ${ANTHROPIC_API_KEY}
enabled: trueAlways read keys from environment variables via ${VAR} — never hardcode literals in YAML. The Anthropic autoconfig already masks the key in logs (security fix in 1.0); don't undo that mask with INFO-level logging in your own configuration code.
Proceed immediately to Step 3.
The starter reads agent shape from agent.* keys in application.yml. Canonical layout (matches examples/spring-boot-kotlin):
agent:
version: "1.0.0"
name: "github-assistant"
model:
id: "gemini-2.5-flash-lite"
options:
temperature: 1.0
system_prompt: |
You are a helpful GitHub assistant.
Always cite the issue number when you reference an issue.
tools:
- type: MCP
id: "GitHub"
options:
docker_image: "ghcr.io/github/github-mcp-server"
docker_options:
GITHUB_PERSONAL_ACCESS_TOKEN: ${GITHUB_PERSONAL_ACCESS_TOKEN}For MCP tools that need secrets (tokens, API keys), reference an env var inside docker_options (or the equivalent for non-Docker MCP runners). Never inline the secret.
Proceed immediately to Step 4.
Inject MultiLLMPromptExecutor (not individual LLMClient beans) into your service code — let it route by model:
@Service
class AgentService(private val executor: MultiLLMPromptExecutor) {
suspend fun run(input: String): String {
val agent = AIAgent(
promptExecutor = executor,
llmModel = ...,
systemPrompt = ...,
)
return agent.run(input)
}
}If you need to override a single provider's client (custom OkHttp config, retry policy), declare a @Bean of that provider's LLMClient type marked @Primary — the autoconfig backs off for that provider.
Proceed immediately to Step 5.
The koog-spring-ai-* family (-common, -starter-model-chat, -starter-model-embedding, -starter-chat-memory, -starter-vector-store) is a bridge to Spring AI's interfaces, not a replacement for koog-spring-boot-starter. Use it when an existing Spring AI app should swap in Koog as the backing executor while keeping Spring AI's APIs at the call site.
If the user mentioned "Spring AI" specifically, confirm which starter family they want before adding the wrong one. Finish here.
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10
scenario-11
scenario-12
scenario-13
scenario-14
scenario-15
scenario-16
scenario-17
scenario-18
scenario-19
scenario-20
scenario-21
scenario-22
scenario-23
scenario-24
scenario-25
scenario-26
scenario-27
scenario-28
scenario-29
scenario-30
scenario-31
scenario-32
scenario-33
scenario-34
scenario-35
scenario-36
scenario-37
scenario-38
scenario-39
scenario-40
scenario-41
scenario-42
scenario-43
skills
add-observability
add-persistence
add-rag
add-structured-output
add-token-budgeting
add-tool
cache-llm-calls
define-prompt
domain-model-subtask-pipeline
references
enable-prompt-caching
handle-agent-events
manage-state
migrate-from-0-x
model-planner-subtasks
persist-chat-history
query-sql-from-agent
scaffold-agent
snapshot-and-restore
test-koog-agents
trace-agent-internals
use-attachments
use-functional-agent
use-llm-node-variants
use-planner
wire-a2a
wire-acp-server
wire-ktor-server
wire-mcp-server
wire-spring-boot