Skip to content

feat(cli): add OpenAI Codex OTEL integration support#183

Merged
AnnatarHe merged 2 commits intomainfrom
feat/codex-otel-integration
Jan 1, 2026
Merged

feat(cli): add OpenAI Codex OTEL integration support#183
AnnatarHe merged 2 commits intomainfrom
feat/codex-otel-integration

Conversation

@AnnatarHe
Copy link
Copy Markdown
Contributor

Summary

  • Add shelltime codex install/uninstall commands for configuring OTEL in ~/.codex/config.toml
  • Improve source detection in AICodeOtel processor using substring matching (supports claude-code variants)
  • Add clientType field to metrics and events for tracking the originating CLI

Test plan

  • Run shelltime codex install and verify ~/.codex/config.toml is created with correct OTEL settings
  • Run shelltime codex uninstall and verify OTEL config is removed
  • Verify existing config files are preserved during install/uninstall
  • Test OTEL data collection from Codex CLI via daemon

🤖 Generated with Claude Code

Add Codex CLI commands for installing/uninstalling OTEL configuration:
- `shelltime codex install` - configures ~/.codex/config.toml with OTEL settings
- `shelltime codex uninstall` - removes OTEL configuration

Improvements to AICodeOtel processor:
- Use substring matching for source detection (supports claude-code variants)
- Add clientType field to metrics and events for better tracking
- Fix timestamp fallback to observed time for log records

Add debug logging for daemon configuration and config file discovery.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @AnnatarHe, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly expands the CLI's observability capabilities by integrating OpenAI Codex with the existing OpenTelemetry system. It provides users with convenient commands to configure and manage Codex telemetry, enhances the daemon's ability to accurately identify and categorize different AI code tool sources, and adds a new field to telemetry data for more granular client tracking. These changes aim to improve the collection and analysis of usage data from various AI-powered coding assistants.

Highlights

  • OpenAI Codex OTEL Integration: New CLI commands shelltime codex install and shelltime codex uninstall have been added to manage OpenTelemetry (OTEL) configuration for OpenAI Codex in ~/.codex/config.toml.
  • Enhanced OTEL Source Detection: The AICodeOtel processor in the daemon now uses substring matching for service.name to more flexibly detect and categorize telemetry sources, supporting various claude and codex variants.
  • Client Type Tracking: A new clientType field has been introduced to OTEL metrics and events, allowing for precise tracking of the originating CLI (e.g., claude_code, codex) in telemetry data.
  • Improved Configuration Handling and Logging: The configuration service now includes better logging for discovered config files and provides warning logs for errors encountered during local config file parsing, preventing silent failures.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@codecov
Copy link
Copy Markdown

codecov Bot commented Jan 1, 2026

Codecov Report

❌ Patch coverage is 6.49351% with 144 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
daemon/aicode_otel_processor.go 0.00% 63 Missing ⚠️
model/codex_otel_config.go 0.00% 55 Missing ⚠️
commands/codex.go 0.00% 17 Missing ⚠️
model/config.go 58.82% 6 Missing and 1 partial ⚠️
cmd/cli/main.go 0.00% 1 Missing ⚠️
cmd/daemon/main.go 0.00% 1 Missing ⚠️
Flag Coverage Δ
unittests 19.49% <6.49%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
cmd/cli/main.go 0.00% <0.00%> (ø)
cmd/daemon/main.go 0.00% <0.00%> (ø)
model/config.go 63.87% <58.82%> (-0.88%) ⬇️
commands/codex.go 0.00% <0.00%> (ø)
model/codex_otel_config.go 0.00% <0.00%> (ø)
daemon/aicode_otel_processor.go 0.00% <0.00%> (ø)

... and 2 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for OpenAI Codex OTEL integration by adding shelltime codex install/uninstall commands. It also improves the OTEL data processing by using substring matching for source detection and adding a clientType field to telemetry data for better tracking. The changes are well-structured, but there are a few critical and high-severity issues related to error handling that need to be addressed. Specifically, a potential issue from ignoring an error when resolving the user's home directory, and inconsistent file read error handling. I've provided suggestions to fix these issues.

Comment on lines +28 to +33
func NewCodexOtelConfigService() CodexOtelConfigService {
homeDir, _ := os.UserHomeDir()
configPath := filepath.Join(homeDir, codexConfigDir, codexConfigFile)
return &codexOtelConfigService{
configPath: configPath,
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

os.UserHomeDir() can return an error if the user's home directory cannot be determined. This error is currently being ignored. If an error occurs, homeDir will be an empty string, and configPath will resolve to a path relative to the current working directory (e.g., ./.codex/config.toml). This could lead to unexpected behavior and potential file permission issues. The error should be handled, and NewCodexOtelConfigService should return an error to the caller.

func NewCodexOtelConfigService() (CodexOtelConfigService, error) {
	homeDir, err := os.UserHomeDir()
	if err != nil {
		return nil, fmt.Errorf("could not get user home directory: %w", err)
	}
	configPath := filepath.Join(homeDir, codexConfigDir, codexConfigFile)
	return 	&codexOtelConfigService{
		configPath: configPath,
	}, nil
References
  1. For platform-independent paths, use filepath.Join to combine segments and os.UserHomeDir() to get the home directory, rather than hardcoding path separators or environment variables like $HOME. The error returned by os.UserHomeDir() must be handled to ensure path correctness.

Comment thread commands/codex.go
func commandCodexInstall(c *cli.Context) error {
color.Yellow.Println("Installing Codex OTEL configuration...")

service := model.NewCodexOtelConfigService()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Following the recommended change to NewCodexOtelConfigService to return an error, this call needs to be updated to handle the potential error. This ensures that if the service cannot be initialized (e.g., because the home directory is not found), the command fails gracefully instead of proceeding with an invalid configuration.

	service, err := model.NewCodexOtelConfigService()
	if err != nil {
		color.Red.Printf("Failed to initialize Codex OTEL config service: %v\n", err)
		return err
	}

Comment thread commands/codex.go
func commandCodexUninstall(c *cli.Context) error {
color.Yellow.Println("Removing Codex OTEL configuration...")

service := model.NewCodexOtelConfigService()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Similar to the install command, the error from the updated NewCodexOtelConfigService must be handled here to ensure the command fails gracefully if service initialization fails.

	service, err := model.NewCodexOtelConfigService()
	if err != nil {
		color.Red.Printf("Failed to initialize Codex OTEL config service: %v\n", err)
		return err
	}

Comment on lines +46 to +50
if data, err := os.ReadFile(s.configPath); err == nil && len(data) > 0 {
if err := toml.Unmarshal(data, &config); err != nil {
return fmt.Errorf("failed to parse existing config: %w", err)
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The error handling for os.ReadFile is inconsistent. In Install, an error from os.ReadFile (e.g., a permission error) is silently ignored, and the function proceeds to create a new configuration, potentially overwriting a file it couldn't read. In Uninstall and Check, such an error would correctly cause the function to fail. The Install function should also handle file read errors explicitly, only ignoring os.IsNotExist errors.

	data, err := os.ReadFile(s.configPath)
	if err != nil && !os.IsNotExist(err) {
		return fmt.Errorf("failed to read existing config file: %w", err)
	}

	if err == nil && len(data) > 0 {
		if err := toml.Unmarshal(data, &config); err != nil {
			return fmt.Errorf("failed to parse existing config: %w", err)
		}
	}

Add support for all Codex-specific OTEL fields that the server expects:
- ConversationID, CallID, EventKind, ToolTokens for session/tool events
- AuthMode, Slug, ContextWindow, ApprovalPolicy, SandboxPolicy for config
- MCPServers, Profile, ReasoningEnabled for conversation_starts
- ToolArguments, ToolOutput, PromptEncrypted for tool_result

Also adds field aliases for Codex OTEL format compatibility:
- http.response.status_code -> statusCode
- user.account_id -> userAccountUuid
- error.message -> error

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@AnnatarHe AnnatarHe merged commit 7ea24ba into main Jan 1, 2026
2 of 3 checks passed
@AnnatarHe AnnatarHe deleted the feat/codex-otel-integration branch January 1, 2026 11:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant