Koog 1.0 idioms, gotchas, and scaffolding skills for Kotlin agents on the JVM
87
88%
Does it follow best practices?
Impact
87%
1.85xAverage score across 45 eval scenarios
Advisory
Suggest reviewing before use
Process steps in order. Do not skip ahead.
implementation("ai.koog:agents-features-opentelemetry:1.0.0")The umbrella koog-agents does not include observability — add it explicitly.
Proceed immediately to Step 2.
Use whichever backend the user named. If the user did not name one, default to OTLP. Do not block on a clarifying question.
Proceed immediately to Step 3. Step 3 writes the actual code to disk; do not stop at prose.
Write the modified agent construction and the dependency to disk — do not respond with prose only. Use explicit Path: labels (same convention as scaffold-agent):
Path: src/main/kotlin/com/example/Main.kt — modified agent construction (or whichever file contains the AIAgent(...) call)Path: build.gradle.kts — appended dependency lineCreate files if they don't exist.
Install inside the AIAgent(...) trailing lambda. The feature is multiplatform (#1942 in 1.0), so the common-code block stays portable; JVM-only knobs come in Step 4.
Langfuse:
import ai.koog.agents.features.opentelemetry.OpenTelemetry
import ai.koog.agents.features.opentelemetry.integration.langfuse.addLangfuseExporter
val agent = AIAgent(
promptExecutor = ...,
llmModel = ...,
systemPrompt = "...",
) {
install(OpenTelemetry) {
setVerbose(true) // emit prompts, completions, and token counts on each span
addLangfuseExporter(
traceAttributes = listOf(
CustomAttribute("langfuse.session.id", System.getenv("LANGFUSE_SESSION_ID") ?: ""),
)
)
}
}OTLP (raw):
import ai.koog.agents.features.opentelemetry.integration.otlp.addOtlpExporter
install(OpenTelemetry) {
addOtlpExporter(endpoint = System.getenv("OTEL_EXPORTER_OTLP_ENDPOINT"))
}Weave / Datadog: the corresponding add<Backend>Exporter functions live in feature/opentelemetry/integration/<backend>/. Use the env-var pattern for keys.
Don't stack two backends — pick one. Stacking compounds traces and inflates cost without adding signal.
Proceed immediately to Step 4.
JVM-only configuration lives on OpenTelemetryConfigJvm extensions (addSpanExporter, addMetricExporter, addMetricFilter). These are NOT visible in common code; if your project is JVM-only the extensions resolve normally:
import ai.koog.agents.features.opentelemetry.OpenTelemetryConfigJvm.addSpanExporter
install(OpenTelemetry) {
addLangfuseExporter(...)
// additional JVM-only span exporter
addSpanExporter(MyCustomExporter())
setShutdownOnAgentClose(true) // opt-in JVM shutdown flush — the auto-hook was removed in 1.0
}The JVM shutdown hook is no longer installed automatically — opt in with setShutdownOnAgentClose(true) if you want traces flushed when the JVM exits.
Proceed immediately to Step 5.
Koog emits these GenAI metrics out of the box (target your dashboards at these names):
gen_ai.client.token.usagegen_ai.client.operation.durationgen_ai.client.tool.countSpan attributes follow current OTel GenAI conventions: gen_ai.input.messages / gen_ai.output.messages (per-message span events were deprecated in 1.0).
If the user wants per-step structured logging on top (e.g., to stdout during development), pair this skill with handle-agent-events. OpenTelemetry is for production signal; events are for development surface.
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
scenario-44
scenario-45
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