← All guides

Agent-driven OpenTelemetry instrumentation

simpletel's bet is that an AI coding agent is a first-class user. This is the recipe as shipped: install the skill, paste one prompt, and let the agent work the ordered steps — with a smoke test before any code change and an exit code, not an eyeball, as the definition of done.

The contract

Three rules hold the whole flow together. The agent never invents a simpletel fact — the endpoint and the x-simpletel-team header both come from simpletel env, which is offline and deterministic. Instrumentation is upstream OpenTelemetry only, so there is no simpletel SDK and no exporter fork. And completion is simpletel verify's zero exit code, never "traces look like they arrived".

Install the skill

The skill is an embedded asset written into each agent's well-known location, byte-identical across agents and version-stamped from the binary so it cannot drift:

simpletel skill install --agent claude|codex|pi
# Pi users can also: pi install git:github.com/willnewby/simpletel-skill

Claude gets skills/<name>/SKILL.md, Codex gets prompts/<name>.md plus a managed AGENTS.md block, and Pi gets the same Agent Skills frontmatter as Claude. The command is idempotent and makes no network call.

The paste-ready prompt

Human to agent, one paste:

Onboard this repository to simpletel.
If the simpletel onboarding skill is not installed, run `simpletel skill install`.
- Log in: `simpletel login`
- Create a team for this repo: `simpletel team create --name <repo-name>`
- Export the env block: `eval "$(simpletel env)"`
- Smoke-test first: `simpletel run -- <start-command>`, then confirm a `cli.run` trace with `simpletel get traces`
- Instrument this app with the upstream OpenTelemetry for its language (zero-code agent preferred), configured only by those OTel env vars
- Run the app, then poll `simpletel get traces --service <service-name>` until the first trace appears, and report the trace id
No simpletel SDK — upstream OpenTelemetry only.

The ordered steps

The skill walks the agent through: confirm a credential (simpletel whoami, and ask the human which login path applies if not); ensure a team (simpletel team list, then team create --name <repo> confirmed with the human); mint the env block (simpletel env — applied as a shell export for a run, or a 0600 env file / compose block / secret store for durability); run the smoke test; detect the language and entrypoint from the build manifest; and instrument with upstream OTel, zero-code agent preferred. The team id in OTEL_EXPORTER_OTLP_HEADERS is the ingest credential — the skill forbids committing it or hard-coding it in a tracked file.

Step zero: know the allowance

Before acting, the skill reads the account's plan and usage with simpletel usage --format json. If the document reports billing_enabled: false the agent notes it and continues — older and self-hosted servers are fine, and the rest of onboarding does not depend on billing. If the account is near or at a limit, the agent says so plainly and surfaces the upgrade_url from the same document. When a command does fail with a plan-limit rejection, the 429 body carries an upgrade_url; the agent presents it to the human and stops that step rather than retrying the same command — raising the plan is the human's decision, not a transient error to wait out.

The smoke test is not optional

Before any code change, the agent runs a trivial command through simpletel run and reads it back with simpletel get traces, confirming a recent cli.run trace. This proves the endpoint, the team header, and network reachability with zero changes to the app. A red smoke test is a credentials or connectivity problem, and the agent fixes that first — it never debugs instrumentation against a broken pipe.

The exit-code gate: simpletel verify

Instrumentation "done" is simpletel verify --service <OTEL_SERVICE_NAME> returning exit 0. It polls until success or the deadline (default 10 minutes; add --deadline 30s for a slow start) and evaluates three rungs:

RungWhat it provesOn failure, check
pipeany fresh trace arrived at allendpoint reachability, the x-simpletel-team credential from simpletel env, and that the exporter points at simpletel. simpletel run -- <cmd> is the quick pipe test.
identitya fresh trace under service.name == your OTEL_SERVICE_NAMEthat OTEL_SERVICE_NAME was exported with the expected value (the report prints the names it saw), and that the env block was applied to the exporter process, not a parent shell.
richnessthat trace carries spans from a library auto-instrumentationauto-instrumentation is not engaged — install the instrumentation packages for the app's dependencies, wrap the real serving process, and exercise real traffic (an idle server emits nothing). Batch exporters flush on a delay (~5s), so wait before concluding it is broken.

A non-zero exit names the failed rung and the fix; agents and CI branch on the code rather than parsing output. That is the whole point — cli.run proves the pipe, but only a rich span proves the app is instrumented. Most onboarding instructions end with "check that traces show up in the dashboard", which is exactly the check an agent cannot do reliably and a human does inconsistently; three ordered booleans and an exit status replace it with something a program can act on and stop at the first real problem.

Framework notes

A zero-code agent comes first wherever one exists: Python (opentelemetry-instrument), Node (--require @opentelemetry/auto-instrumentations-node/register), Java (-javaagent), and .NET's automatic-instrumentation shim all add tracing with no source edit. Go and Rust have no zero-code agent, so the agent adds the smallest upstream SDK bootstrap — for Go, the otel + otlptracehttp + sdk/trace setup reading the OTEL_EXPORTER_OTLP_* env vars — at the entrypoint and flushes it on exit. Bootstrap and wiring only; manual spans are a follow-up once data flows.

The handoff summary

simpletel verify exiting 0 is the end of the work, not the end of onboarding. The agent closes by printing four fields, in order: the resolved team id (20-hex), the service name the app now exports under, the verification result plus the first verified trace id from its verified: service=… trace=… line, and the console URL (simpletel console). Then one line of next-step: open the console's errors-only view to catch problems early. Never leave the human with just "it worked".