cd /news/ai-agents/i-can-see-your-goose · home topics ai-agents article
[ARTICLE · art-72839] src=adrianavillela.netlify.app ↗ pub= topic=ai-agents verified=true sentiment=↑ positive

I Can See Your Goose!

AAIF's Goose agent now supports OpenTelemetry observability, enabling developers to trace and understand AI agent decision-making. The integration, detailed in a tutorial by AAIF, uses Goose v1.43.0 with the Claude ACP provider and Rust's OpenTelemetry SDK to provide visibility into agent actions, addressing common frustrations with opaque AI behavior.

read7 min views7 publishedJul 24, 2026
I Can See Your Goose!
Image: Adrianavillela (auto-discovered)

Making AAIF's Goose Observable with OpenTelemetry

If you’ve used AI agents for tech-y things (software development, SRE type stuff, etc), you’ve probably found yourself in a yelling match at some point with your agent trying to understand why the hell it decided to take a particular course of action. Especially if that course of action is destructive or mischievous, like making code changes without permission, for example. Which is why having observable agents is important.

Now, this is a fairly broad topic. There are lots of different agentic ecosystems out there. So today, I’ll dig into one specific use case: enabling OpenTelemetry (OTel) on AAIF’s Goose to help make your Goose agents observable.

Let’s dig in!

Goose Overview #

Enabling OTel on Goose #

For your convenience, I have a lovely GitHub repository to accompany this tutorial, including the dev container configuration. If you choose to use the dev container, you will have all of the tools that you need for this tutorial.

Set up Goose

The instructions in this section are for setting up Goose with with the Claude ACP provider, which is a wrapper for Claude Code.

FUN FACT:ACP stands for Agent Client Protocol. It’s an open standard that allows AI agents to talk to each other.

1. Install Goose

First things first, you need to set up Goose. When the dev container first builds, it donwloads and installs Goose, and then Goose prompts you to set it up.

You don’t need to run the code snippet below, as it’s already done for you on dev container initial build, but I’ve included it for you so you can see how it’s being installed.

GOOSE_RELEASE="v1.43.0"
curl -fsSL https://github.com/aaif-goose/goose/releases/download/${GOOSE_RELEASE}/download_cli.sh | bash

2. Configure your provider

These steps show you how to set up Goose with the Claude Code provider.

NOTE:If you need to configure your provider again, rungoose configure

How would you like to set up your provider?:Manual Configuration

Which model provider should we use?:Claude Code CLI

Provider Claude Code CLI requires CLAUDE_CODE_COMMAND, please enter a value:claude

Select model:claude-sonnet-4-6

Select thinking effort:Low - Better latency, lighter reasoning

Success!!

Unfortunately, as you were making your selection, you may have noticed that the Claude CLI is deprecated. On top of that, we don’t have the option to select Claude ACP

. ARRGH!! Fortunately, I found a workaround.

First, open your Goose config.yaml file, and locate the code snipped below:

active_provider: claude-code
providers:
  claude-code:
    enabled: true
    model: claude-sonnet-4-6
    configured: true

Replace claude-code

with claude-acp

. Your modified block should look like this:

active_provider: claude-acp
providers:
  claude-acp:
    enabled: true
    model: sonnet
    configured: true

You also need to globally install the Claude ACP npm package:

npm install -g @agentclientprotocol/claude-agent-acp

For more info, check out out the Goose ACP docs.

3. Login to Claude

Open a new terminal window, then start a Claude Code session via the Claude CLI by typing claude

, and following the login instructions provided.

4. Start Goose

Once Claude is authenticated, open a new terminal window and start Goose:

goose session

Feel free to ask it a test question. I always like to ask “how many folders in my directory?”.

Enabling OpenTelemetry for Goose

Fun fact: Goose is written in Rust, and is it so happens that it ships with built-in OpenTelemetry instrumentation, courtesy of the Rust OTel SDK. This allows Goose to emit OTel traces, logs, and metrics.

But you need to enable it.

1. Enable telemetry

Upon initial setup, Goose may have given you the following option:

Enable or disable anonymous usage data collection

It’s kind of confusing, and if you’re like me, you might have disabled it initially. It turns out that you need this setting enabled for OTel telemetry emission. Never fear, because there’s a way to enable it after the fact.

Open ~/.config/goose/config.yaml, and find the configuration called

GOOSE_TELEMETRY_ENABLED

, and set it to true

:

GOOSE_TELEMETRY_ENABLED: false

GOOSE_TELEMETRY_ENABLED: true

But that’s only part of the story. We also need to configure a few OTel environment variables.

2. Configure environment variables

The OTel environment variables tell OTel where to send the telemetry. These are the ones we need:

OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318"
OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"

Where:

OTEL_EXPORTER_OTLP_ENDPOINT

is the destination of our telemetry. In our case, we’re sending the telemetry to anOTel Collector. The Collector is configured to send telemetry data toJaeger(traces only) andDynatrace(traces, logs, metrics).OTEL_EXPORTER_OTLP_PROTOCOL

is the protocol we’re using for sending our OTel data. OTel supports both gRPC and HTTP. In this case, we’re using HTTP. If we were sending via gRPC, the value ofOTEL_EXPORTER_OTLP_PROTOCOL

would begrpc

, and our endpoint would behttp://localhost:4317

(the OTel Collector listens on port4317

for gRPC).

Full disclosure:I work at Dynatrace and therefore have access to a Dynatrace environment. Obviously, you don’t have to go that route. To make things easier, I have split off the Dynatrace configuration so that you can exclude it if you won’t want to use it.

To configure the environment variables, create a copy of .env.example:

cp .env.example .env

If you don’t want to go the Dynatrace route, you don’t need to make any other environment variable configurations.

If you choose to also use Dynatrace as your observability backend, uncomment and replace the details for the following environment variables:

DT_ENDPOINT

:your Dynatrace endpointDT_API_TOKEN

:your Dynatrace API token

3. Start OTel components

Now we’re ready to start the OTel Collector and Jaeger. This is done via a docker-compose.yaml, which starts two containers:

Service Image Exposed ports
otel-collector otel/opentelemetry-collector-contrib:0.128.0 4317 (gRPC), 4318 (HTTP)
jaeger jaegertracing/jaeger:2.7.0 16686 (UI)

NOTE:If you would like to exclude the Dynatrace components, comment out lines referencing the Dynatrace Collector configuration from[:]docker-compose.yaml

Before:

otel-collector:
  image: otel/opentelemetry-collector-contrib:0.128.0
  command:
    - "--config=/etc/otel/config.yaml"
    - "--config=/etc/otel/config-dt.yaml"
  volumes:
    - ./src/otel/otel-collector-config.yaml:/etc/otel/config.yaml
    - ./src/otel/otel-collector-config-dt.yaml:/etc/otel/config-dt.yaml

After:

otel-collector:
  image: otel/opentelemetry-collector-contrib:0.128.0
  command:
  - "--config=/etc/otel/config.yaml"
  volumes:
    - ./src/otel/otel-collector-config.yaml:/etc/otel/config.yaml

Now you’rea ready to run the script:

./src/scripts/start-otel.sh .env

This starts up Jaeger and the OTel Collector.

Jaeger UI: http://localhost:16686

Dynatrace UI: https://<your_tenant_id>.live.dynatrace.com

5. Start Goose with OTel

You’ll need to ensure that the values from your .env

file are loaded before you start your Goose session, which you can do like this:

export $(grep -v '^#' .env | xargs) && goose session

Then ask Goose a question! I asked my favourite question:

how many folders in my directory?

In your observability backend, you will be able to see traces, logs, and metrics for Goose, by filtering on attribute service.name

= goose

.

Goose prompts and results are captured in OTel spans (children of a trace):

  • Prompts are stored in the trace_input

anduser_message

fields of the span - Prompt results are stored in the trace_output

  • The prompt input span is disconnected from the prompt output trace (i.e. they’re not part of the same trace)
  • All prompts in the same Goose session have the same sesison.id

Here’s a sample trace output from Jaeger:

Here’s a sample trace output from Dynatrace using Dynatrace Query Language (DQL) in a Notebook:

As you can see, in both Jaeger and Dynatrace, there are separate traces for the request (prompt) and response (result), which kind of sucks for correlation.

Goose also emits logs, which you can see in Dynatrace. Again, I used DQL in a Notebook:

And of course, metrics (again, in Dynatrace using DQL in a Notebook):

The metrics don’t look particularly useful in this format because it’s just the metric name and metadata. I wasn’t looking to do anything fancy other than see that the metrics were being emitted. You’ll find them more useful in a timeseries.

Final Thoughts #

Being able to capture telemetry from a Goose session is very useful, especially when you’re running your agents in autonomous mode via Goose Recipes. You might not be able to keep your agent from doing something completely dumb, but you can at least understand what the hell led to that decision, and most importantly, what it did.

As far as Goose telemetry goes, I didn’t find the Goose logs particularly useful. Most of the meaty bits for my personal use cases were in the spans. As I noted earlier, the only thing that I found annoying is how the prompt trace is not correlated to the prompt output trace, which means that you can’t really correlate them easily unless your observability backend can support fancy querying. Jaeger can’t. Dynatrace may likely be able to, but I have to play around with it a bit more. That’s another adventure for another day!

And now, I will leave you with a very on-theme photo of a goose living its best life. Photo taken by my daughter.

Until next time, peace, love, and code. 🖖💜👩💻

── more in #ai-agents 4 stories · sorted by recency
── more on @aaif 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/i-can-see-your-goose] indexed:0 read:7min 2026-07-24 ·