Instrument your code with an AI agent
Give a coding agent one prompt and it adds OpenTelemetry auto-instrumentation to your service, pointed at sigiro. Works with Claude Code, OpenCode, and Codex.
If your code has no OpenTelemetry in it yet, don't add it by hand. Paste the prompt below into a coding agent and it will detect your framework, install the official auto-instrumentation, and point the exporter at sigiro.
Works with Claude Code, OpenCode, Codex, or any coding agent that can edit files and run your package manager.
Before you start
You need a sigiro server to send to — sigiro serve, or the Docker command from the
quickstart. A self-hosted server needs no key. Only the hosted
service does, shaped sk_<tenant>_<random>.
Auto-instrumentation exists for Python, Node.js, Java, .NET and Ruby. Go has no runtime agent, so there the work is a few lines of SDK setup instead.
1. Give the agent this prompt
Replace the endpoint, and drop the key line entirely unless you are on hosted.
Instrument this codebase for sigiro observability.
SIGIRO ENDPOINT: http://localhost:4318 (replace with your OTLP ingest address)
HOSTED API KEY: sk_<tenant>_<random> (omit entirely for a self-hosted server)
Goal: add OpenTelemetry auto-instrumentation so this service emits traces,
metrics, and logs to sigiro. Make the minimum change that works — prefer
auto-instrumentation over hand-written spans.
Rules:
- Detect the language and framework automatically
- Use official OTel auto-instrumentation where it exists (Python opentelemetry-instrument,
Java javaagent, Node.js auto-instrumentations-node, etc.)
- If auto-instrumentation is not available for this language/framework, add
manual OTel SDK spans for HTTP handlers and database calls
- Set OTEL_EXPORTER_OTLP_ENDPOINT to the sigiro OTLP HTTP endpoint (:4318)
- For hosted sigiro only, set OTEL_EXPORTER_OTLP_HEADERS with the tenant bearer token
- Set OTEL_SERVICE_NAME to identify this service (use the existing service name or repo name)
- Use the existing package manager (pip, npm, Maven, Gradle, gem, go get)
- For hosted sigiro, do NOT hardcode the tenant key — read it from SIGIRO_API_KEY
- If a file already initializes the OTel SDK, update it rather than re-initializing
- Add SIGIRO_API_KEY to .env.example only for a hosted deploymentIf the agent guesses the language wrong, tell it outright:
Language: <python|nodejs|java|dotnet|ruby|go>
Framework: <fastapi|express|spring-boot|rails|...>2. What each language gets
| Language | Approach | Covers |
|---|---|---|
| Python | opentelemetry-instrument CLI + distro | HTTP (FastAPI, Flask, Starlette), DB (psycopg2, asyncpg), Redis |
| Node.js | @opentelemetry/auto-instrumentations-node | HTTP (Express, Fastify), DB (pg, mysql2, mongoose) |
| Java | opentelemetry-javaagent.jar | HTTP (Servlets, Spring), DB (JDBC), JVM metrics |
| .NET | OpenTelemetry.AutoInstrumentation startup hook | HTTP (ASP.NET Core), DB (EF Core) |
| Ruby | opentelemetry-instrumentation-all gem | HTTP (Rails), DB (ActiveRecord), Sidekiq |
| Go | Manual SDK setup | HTTP spans via middleware, DB spans via OTel hooks |
Go needs the tracer wired up by hand and every handler wrapped:
import (
"context"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
)
func initTracer(ctx context.Context) (func(context.Context) error, error) {
exporter, err := otlptracehttp.New(ctx,
otlptracehttp.WithEndpoint("localhost:4318"),
otlptracehttp.WithInsecure(),
)
if err != nil {
return nil, err
}
tp := sdktrace.NewTracerProvider(sdktrace.WithBatcher(exporter))
otel.SetTracerProvider(tp)
return tp.Shutdown, nil
}
// Wrap each handler so its spans carry the route name:
http.Handle("/checkout", otelhttp.NewHandler(
http.HandlerFunc(checkoutHandler), "checkout",
))WithInsecure() is what makes the exporter talk plain HTTP to a local server. Drop it
for hosted, which is TLS, and add the bearer token with
otlptracehttp.WithHeaders(map[string]string{"Authorization": "Bearer " + key}).
3. Check it worked
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 \
OTEL_SERVICE_NAME=my-service \
<your-app-start-command>Then ask sigiro what it has seen:
curl http://localhost:9999/v1/servicesYour service should appear within a few seconds of real traffic. Once it does,
sigiro investigate my-service has something to work with.
If nothing shows up: confirm the port (:4318 HTTP, :4317 gRPC), run sigiro status
to check the server is healthy, and read your service's own logs for OTel startup
errors — a misconfigured exporter usually says so loudly at boot. On hosted, check the
header is exactly Authorization: Bearer sk_<tenant>_<random>. A self-hosted server
ignores auth headers entirely, so a bad key there fails silently rather than 401ing.
Tell the agent what not to do
Agents reach for more than you want here. Worth stating up front:
- Don't install an OTel Collector. sigiro is the collector.
- Don't add per-endpoint manual spans. Auto-instrumentation already covers them.
- Don't touch database connection strings or business logic.
- Don't set up dashboards or alert configs. There aren't any.
The whole job is: detect the framework, install auto-instrumentation, point it at sigiro.
Point Claude Code itself at sigiro
Claude Code emits its own OpenTelemetry. To watch your sessions, set these in the
environment that launches it — a shell profile, an .envrc, or a wrapper script:
export CLAUDE_CODE_ENABLE_TELEMETRY=1
export CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1
export OTEL_METRICS_EXPORTER=otlp
export OTEL_LOGS_EXPORTER=otlp
export OTEL_TRACES_EXPORTER=otlp
export OTEL_EXPORTER_OTLP_PROTOCOL=grpc
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317For hosted, add OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer ${SIGIRO_API_KEY}"
and keep the key out of anything committed.
This instruments Claude Code, not the commands it runs. Apps it starts through its shell tool may not inherit these variables, so instrumented services still need their own exporter settings.
Point Codex itself at sigiro
Codex reads telemetry settings from its own config rather than the environment. In
~/.codex/config.toml:
[otel]
environment = "dev"
log_user_prompt = false
exporter = "otlp-grpc"
[otel.exporter."otlp-grpc"]
endpoint = "http://localhost:4317"For hosted, add headers = { authorization = "Bearer ${SIGIRO_API_KEY}" } and set
SIGIRO_API_KEY in the environment that starts Codex. The same caveat applies: this
covers Codex, not the services it edits.
Next
- Quickstart — ask what changed and why
- Hosted beta — if you'd rather not run it yourself
Quickstart
Run sigiro with one docker command, point OpenTelemetry at it, then ask it what changed and why. Five minutes, no collector, no config.
Hosted beta
Ship OpenTelemetry to hosted sigiro with a tenant key and query it back with SQL — no infrastructure to run. Onboarding is manual during the invited beta.