GitHub Copilot CLI session tracing
Send GitHub Copilot CLI agent sessions to Future AGI with Copilot's built-in OpenTelemetry export. Prompts and tool arguments stay off by default.
About
GitHub Copilot can export every agent interaction as an OpenTelemetry trace: one invoke_agent span for the user message, one chat span per model call, and one execute_tool span per tool call. Point that export at Future AGI and each Copilot agent turn shows up as a trace in Observe, with model names, token counts, tool names, and timings. Prompts, responses, and tool arguments are not exported unless you turn content capture on.
This guide covers Copilot CLI 1.0.98 only, using its native OTLP/HTTP exporter. VS Code Copilot Chat is a separate surface and has no Future AGI setup instructions on this page.
See GitHub’s CLI OpenTelemetry reference for the exporter settings.
What you get
One Copilot agent turn becomes one trace. A Copilot CLI turn that lists a folder and reads a file looks like this in Future AGI:
invoke_agent conversation id, total tokens, turn count
├── chat gpt-6-luna model, input/output/cached tokens, finish reason
├── execute_tool glob tool name, tool call id
├── execute_tool bash bash tool name, tool call id, exit code
├── chat gpt-6-luna
├── execute_tool view
└── chat gpt-6-luna
| Span | Key attributes (content capture off) |
|---|---|
invoke_agent | gen_ai.conversation.id, gen_ai.usage.input_tokens, gen_ai.usage.output_tokens, github.copilot.turn_count, github.copilot.agent.type, error.type on failure |
chat <model> | gen_ai.request.model, gen_ai.response.model, gen_ai.usage.* tokens (including cache read/write), gen_ai.response.finish_reasons, gen_ai.response.time_to_first_chunk |
execute_tool <tool> | gen_ai.tool.name, gen_ai.tool.call.id, gen_ai.tool.type, process.exit.code for shell tools, error.type on failure |
| Span status / hook errors | Raw failure text may be present even with content capture off: status messages, exception events, or CLI github.copilot.hook.error_message |
Prerequisites
- A Future AGI account and your API key and secret key (Settings > API Keys).
- GitHub Copilot access on your GitHub account. Use an account entitled to Copilot CLI.
- Install the CLI version used by this guide:
npm install -g @github/copilot@1.0.98, thencopilot loginonce.
Set up the Copilot CLI
Set the exporter variables
Set the exporter variables on the Copilot process only, with a copilot shell function (add it to ~/.zshrc or ~/.bashrc; it holds no keys):
copilot() {
OTEL_EXPORTER_OTLP_ENDPOINT="https://api.futureagi.com/tracer" \
OTEL_EXPORTER_OTLP_HEADERS="X-Api-Key=${FI_API_KEY},X-Secret-Key=${FI_SECRET_KEY}" \
OTEL_RESOURCE_ATTRIBUTES="project_name=my-copilot-sessions,project_type=observe" \
command copilot --secret-env-vars=FI_API_KEY,FI_SECRET_KEY,OTEL_EXPORTER_OTLP_HEADERS "$@"
}Setting OTEL_EXPORTER_OTLP_ENDPOINT turns Copilot’s exporter on. Copilot appends /v1/traces, so the base URL ends at /tracer. project_name is required: Future AGI creates the project on the first export and rejects spans without it.
--secret-env-vars removes the named variables from the shell commands and MCP servers Copilot starts, and redacts their values from Copilot’s output. Copilot’s own exporter still uses them. Copilot CLI 1.0.98 already keeps OTEL_* variables out of its shell commands; the flag is what keeps FI_API_KEY and FI_SECRET_KEY out.
The function reads FI_API_KEY and FI_SECRET_KEY from the shell you run it in, so set them only for that terminal session (for example from your password manager’s CLI), not in a shell profile. The trade-off: other programs you start from that terminal can still read the two keys, but only Copilot gets the exporter settings.
Avoid the simpler export OTEL_EXPORTER_OTLP_* in your shell. Then every program started from that shell, including other OpenTelemetry-instrumented tools, sends its telemetry to Future AGI with your keys.
Run an agent session
Start an interactive session in a folder whose contents you are comfortable sharing with your model provider:
cd ~/code/my-project
copilotAsk: List the files in this folder and read README.md, then summarize it in one sentence. Review each tool permission before approving it. Each message you send becomes its own invoke_agent trace.
Note
With -p, Copilot exits after the answer and waits about one second for the exporter, so the first trace can be lost. Create the project in Future AGI before the first -p run, or start with an interactive session.
Find the trace
Open Observe in Future AGI and select the my-copilot-sessions project. The newest trace has an invoke_agent root with chat and execute_tool children. Filter on gen_ai.conversation.id to see every turn from one Copilot session.
The repository example examples/coding-agents/github-copilot includes the same function in copilot-otel.sh.
Privacy
By default Copilot exports mostly metadata: model names, token counts, durations, tool names, and IDs. Prompt and tool message bodies are off by default. However, some vendor fields remain free text even when content capture is off, including hook command paths and raw failure text.
Other fields you should know about:
| Field | When it is sent | Notes |
|---|---|---|
enduser.pseudo.id (CLI) | When available | Pseudonymous Copilot user ID, not an email or login |
github.copilot.git.repository, .branch, .commit_sha (CLI) | When the workspace is a Git repository | Repository remote URL, current branch and commit |
github.copilot.context.skills, .custom_agent_names, .mcp_server_names (CLI) | When the session uses them | Skill names, custom agent names and hashed MCP server names |
github.copilot.skill.invoked event and execute_tool skill <name> span (CLI) | When the agent runs a skill | With content capture off: the skill name (gen_ai.skill.name), what triggered it (github.copilot.skill.invocation_trigger), and where it was loaded from (github.copilot.skill.source, for example project). The skill file’s location (gen_ai.skill.source.uri, a local file:// path), description, and body (github.copilot.skill.content) are added only when content capture is on. |
Status messages and github.copilot.hook.error_message | On failures | Raw failure text can contain paths or hook/tool output |
Note
Teams with strict data rules can remove the hook command, status messages, and hook error text before they reach Future AGI. Point Copilot’s exporter at your own OpenTelemetry Collector (otelcol-contrib 0.162.0) and add this transform processor to its traces pipeline. Spans keep their error status; only the text is removed.
processors:
transform/copilot-redact:
error_mode: ignore
trace_statements:
- context: span
statements:
- delete_key(attributes, "copilot_chat.hook_command")
- set(status.message, "") where status.message != ""
- context: spanevent
statements:
- delete_key(attributes, "github.copilot.hook.error_message")
- delete_key(attributes, "exception.message")
- delete_key(attributes, "exception.stacktrace")Have the collector forward to https://api.futureagi.com/tracer/v1/traces with the X-Api-Key and X-Secret-Key headers. Future AGI accepts gzip-encoded and uncompressed OTLP, so the exporter’s default compression works.
To capture prompt and tool content for one CLI session, run OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT=true copilot through the wrapper. Opt in only in a trusted environment.
With content on, spans add gen_ai.input.messages, gen_ai.output.messages, gen_ai.system_instructions, gen_ai.tool.definitions, gen_ai.tool.call.arguments, and gen_ai.tool.call.result. In Future AGI they appear in the span’s Attributes, not in the trace list’s Input and Output columns. They can contain source code, file contents, secrets that appear in your files, and local paths such as your working directory and skill file locations.
What is not available
- Inline completions (ghost text), next edit suggestions, and Copilot code review do not produce these traces.
- The Copilot cloud agent that works on GitHub and opens pull requests is not covered. Its sessions run on GitHub, not on your machine.
- Session grouping. Future AGI’s Sessions view groups traces by the
session.idspan attribute. If spans containgen_ai.conversation.idbut notsession.id, each user message is a separate trace and Sessions stays empty. Filter ongen_ai.conversation.idto follow one conversation. - Cost in currency.
github.copilot.costis a billing multiplier andgithub.copilot.nano_aiucounts AI units. Neither is a dollar amount, and Future AGI does not convert them. - Metrics and events. Copilot also exports OTel metrics. The Future AGI collector accepts traces only, so metric exports are rejected with HTTP 404 (Copilot logs
HTTP export failed with status code: 404at exit). Traces are not affected. - Span type for
invoke_agent. Future AGI classifieschatspans as LLM andexecute_toolspans as tools; theinvoke_agentroot shows typeunknown. - Standalone
custom_notificationtraces. Copilot CLI can export a one-spancustom_notificationtrace for shell completion, idle, or permission notifications. Future AGI shows it as type unknown; it is safe to ignore or filter. - The local file and SQLite exporters (
COPILOT_OTEL_FILE_EXPORTER_PATH) are debugging aids, not the setup path.
This page is about Copilot as an application. It is not a wrapper for GitHub Models or for model calls your own code makes; use a traceAI integration for those.
Troubleshooting
| Symptom | Fix |
|---|---|
| Spans rejected with 401 or 403 | OTEL_EXPORTER_OTLP_HEADERS must be X-Api-Key=...,X-Secret-Key=... with no spaces or quotes inside the value. |
Spans rejected with a project_name error | Add project_name=... to OTEL_RESOURCE_ATTRIBUTES. |
| 404 from the collector | If no traces arrive and the 404 is for traces (not meter shutdown), the endpoint is a base URL. Use https://api.futureagi.com/tracer, not .../tracer/v1/traces. A meter-shutdown 404 is expected because Future AGI accepts traces only. |
| Prompts are visible in spans | Content capture is on. Unset OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT or COPILOT_OTEL_CAPTURE_CONTENT before running the CLI. |
Next steps
- Observe overview to filter, search, and evaluate traces.
- traceAI integrations for tracing your own LLM application code.
Questions & Discussion