# Add Custom Span Attributes with OpenTelemetry from a Linear Issue

Yes. An agent picks up the Linear issue, adds app.order.amount and app.order.items.count on the PlaceOrder span, tests them and opens a pull request.

[Run this on Rush](https://cloud.getrush.ai/run/add-custom-span-attributes/opentelemetry/), in a Project that has your repository.

## What the agent does

The run starts from the repository URL in `resources`: the agent clones it into its own cloud sandbox and reads the checkout service the way a new maintainer would. In a polyglot store like `open-telemetry/opentelemetry-demo` the checkout service lives under `src/checkout/`, is Go 1.26.0 per `go.mod`, and pulls `go.opentelemetry.io/otel` at v1.47.0. The service README tells a developer to build with `docker compose build checkout` from the repo root, and `compose.yaml` already names the `checkout` image and sets `OTEL_SERVICE_NAME=checkout`.

PlaceOrder is the span the issue names. In `src/checkout/main.go`, `PlaceOrder` already sets `user.id`, currency, payment fields, then later `demo.order.id`, `demo.shipping.amount`, `demo.order.amount` and `demo.order.items.count` on the active span via `span.SetAttributes`. The issue asks for the `app.*` names specifically: `app.order.amount` and `app.order.items.count` on that same PlaceOrder span, so a dashboard or alert that keys on the app namespace can find them without parsing the demo.* keys.

The agent adds those two attributes next to the existing order totals, using `attribute.Float64` for the amount and `attribute.Int` for the item count, sourced from the same `totalPriceFloat` and `len(prep.orderItems)` values the demo attributes already use. It leaves the `demo.*` keys in place so existing demo dashboards keep working, and it does not touch the Kafka producer spans or the shipping preparation helper.

Proving it means extending `src/checkout/main_test.go`, which today covers email timeout bounds, health checks and graceful gRPC stop, not span attributes. The agent adds a test that drives PlaceOrder against a checkout with stubbed cart, currency, payment and shipping clients, reads the recorded span through the OpenTelemetry SDK's in-memory exporter, and asserts both `app.order.amount` and `app.order.items.count` are present with the expected types. Then it runs `go test ./...` in `src/checkout` and `docker compose build checkout` from the root.

## Start it with one API call

`POST https://api.prix.dev/o/{org}/sessions`

```json
{
  "agent": "claude",
  "input": "A Linear issue labeled agent says: \"Add Custom Span Attributes with OpenTelemetry. In the checkout service, add app.order.amount and app.order.items.count attributes to the PlaceOrder span and a test that asserts they are set.\" Do the work in this repository, add tests for it, run docker compose build for the touched services, and open a pull request that links back to the issue.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-app"
    }
  ]
}
```

1. **Get an API key.** In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
2. **Send the request.** POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
3. **Read what came back.** Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.

## What comes back

What comes back is a pull request. Its diff touches `src/checkout/main.go` with the two `app.order.*` attributes on PlaceOrder, and `src/checkout/main_test.go` with a span-attribute assertion. The description quotes the issue and links back to it.

The checks on the pull request run `go test` for checkout and the compose build the service README documents. A reviewer reads the diff for three things: the attribute keys match the issue exactly, the values come from the order total and item count already computed in PlaceOrder, and the test fails if either attribute is removed. The existing `demo.order.amount` and `demo.order.items.count` attributes stay.

The session read keeps the record behind the pull request: every command the agent ran with its output, including the Go test and the compose build. Anyone who questions the checks can read exactly how they were run.

## Run it on every Linear issue labelled agent

The Project's automation turns the label into the run. In the console, add an automation with a Linear trigger on `linear.issue.labeled` filtered to the `agent` label and this prompt; each labelled observability issue starts its own run in its own sandbox and opens its own pull request against the demo monorepo.

If the automation is not wanted, a small server can do the same: receive Linear's issue webhook, put the issue text into `input` in place of the quoted text, and POST to `/o/{org}/sessions` with the OpenTelemetry demo repository in `resources`. A `run.completed` webhook on the API key then posts the result URL when the span-attribute change is ready to review.

## Why run it on Rush?

On a laptop this job is a chain of setup: a deep clone of a multi-service demo, a Go toolchain that matches `go 1.26.0`, and Docker available for `docker compose build checkout`. Each run on Rush boots its own sandbox with that already in reach, runs `go test` and the compose build itself, and keeps every command and its output, so the proof of the span attributes is the run's own record rather than a paste into a pull request comment.

Instrumentation tickets rarely wait for a quiet afternoon. Issues labelled in one triage pass become one run each, in one sandbox each, each on its own branch with its own pull request, instead of several engineers sharing one Docker daemon and one checkout of the demo.

## Frequently asked questions

### The PlaceOrder span already sets demo.order.amount. What changes?

Those `demo.*` attributes stay. The issue asks for `app.order.amount` and `app.order.items.count` as well, so tools that filter on the app namespace can find the order total and item count without depending on the demo prefix.

### Which service does the agent change?

Only `src/checkout/`. The agent reads `go.mod` and `main.go` there, extends PlaceOrder and `main_test.go`, and builds with `docker compose build checkout`. Other services in the demo are left alone.

### How are the attributes tested without a live collector?

The new test records spans with the OpenTelemetry SDK's in-memory exporter inside the Go test process. No Jaeger or OTLP endpoint has to be up for the assertion to run.

### Will the agent regenerate protobufs?

No. The attribute change is in the Go handler, not in `pb/` or `genproto/`. The agent does not run `make docker-generate-protobuf` unless the issue asks for a schema change.
