Skip to content

Conversation

@andrewm4894
Copy link
Owner

@andrewm4894 andrewm4894 commented Jan 15, 2026

Summary

  • Add opt-in PostHog instrumentation that tracks agent workflows when POSTHOG_API_KEY is set
  • Integrates with OpenAI Agents SDK via posthog.ai.openai_agents.instrument() for automatic tracing
  • Add python-dotenv for .env file loading in CLI

What's Tracked

When enabled, PostHog captures:

  • $ai_trace - Full agent workflow traces
  • $ai_generation - LLM API calls with model, tokens, input/output
  • $ai_span - Agent execution, tool calls, and handoffs
  • Latency metrics for all operations

Configuration

# Enable by setting these env vars (or in .env file)
POSTHOG_API_KEY=phc_...
POSTHOG_HOST=https://us.posthog.com  # optional, defaults to us.posthog.com
POSTHOG_DEBUG=true  # optional, enables debug logging

Test plan

  • Verify standup works without PostHog configured (no changes to existing behavior)
  • Verify traces appear in PostHog when API key is set
  • Verify agent handoffs, tool calls, and generations are captured
  • Run make check (lint, type-check, tests pass)

Summary by CodeRabbit

  • New Features

    • Added optional PostHog instrumentation for tracing and analytics. Users can configure via environment variables (POSTHOG_API_KEY, POSTHOG_HOST, POSTHOG_DISTINCT_ID). Sensitive data tracing is now enabled for enhanced observability.
  • Documentation

    • Added setup guide for PostHog instrumentation configuration.

✏️ Tip: You can customize this high-level summary in your review settings.

Add opt-in PostHog instrumentation that tracks agent workflows, LLM
generations, tool calls, and handoffs. Enabled by setting POSTHOG_API_KEY
environment variable.

- Add instrumentation.py with setup_posthog() using posthog-python SDK
- Integrate with OpenAI Agents SDK via posthog.ai.openai_agents.instrument()
- Add python-dotenv for .env file loading in CLI
- Add posthog as optional dependency group
- Document PostHog env vars in .env.example and CLAUDE.md
@coderabbitai
Copy link

coderabbitai bot commented Jan 15, 2026

📝 Walkthrough

Walkthrough

The pull request introduces optional PostHog instrumentation to the project. A new instrumentation module provides setup and shutdown functions, runtime and optional dependencies are added, environment variables are loaded at startup, and instrumentation is initialized in key workflows with sensitive data tracing enabled.

Changes

Cohort / File(s) Summary
Configuration & Dependencies
.env.example, pyproject.toml
Added PostHog environment variable templates (API key, host, distinct user ID). Added python-dotenv>=1.0.0 runtime dependency and posthog>=7.5.0 optional dev dependency.
Documentation
CLAUDE.md
Added PostHog instrumentation configuration guide describing environment variables, host setup, and SDK installation instructions.
Environment Loading
src/github_standup_agent/cli.py
Integrated load_dotenv() call at startup to ensure environment variables are available early in execution.
Instrumentation Module
src/github_standup_agent/instrumentation.py
New module implementing PostHog instrumentation with setup_posthog(), shutdown_posthog(), and is_enabled() functions. Supports lazy importing, debug mode, and graceful error handling for missing dependencies.
Workflow Integration
src/github_standup_agent/runner.py
Initialized PostHog instrumentation in standup generation and interactive chat workflows using GitHub username as distinct ID. Enabled trace_include_sensitive_data=True in both workflow RunConfig instances.

Sequence Diagram

sequenceDiagram
    participant CLI
    participant Env as Environment
    participant PostHog as PostHog Setup
    participant Workflow as Workflow Runner
    participant Client as PostHog Client
    participant Tracer as Instrumentation Processor

    CLI->>Env: load_dotenv()
    Env-->>CLI: environment variables loaded
    Workflow->>PostHog: setup_posthog(github_username)
    PostHog->>Env: check POSTHOG_API_KEY
    alt API Key Present
        PostHog->>Client: initialize PostHog client
        Client-->>PostHog: client ready
        PostHog->>Tracer: create instrumentation processor
        Tracer-->>PostHog: processor ready
        PostHog-->>Workflow: True (enabled)
    else API Key Missing
        PostHog-->>Workflow: False (disabled)
    end
    Workflow->>Workflow: execute with tracing (if enabled)
    Workflow->>PostHog: shutdown_posthog()
    PostHog->>Client: flush and close
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 PostHog traces hop and bound,
Through workflows, data flowing 'round,
With dotenv loading secrets true,
Our agent sings instrumentation's tune! 🎵

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the primary change: adding optional PostHog instrumentation for agent tracing, which is the main objective of this changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Warning

Review ran into problems

🔥 Problems

Git: Failed to clone repository. Please run the @coderabbitai full review command to re-trigger a full review. If the issue persists, set path_filters to include or exclude specific files.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@pyproject.toml`:
- Around line 40-42: The optional dependency entry posthog = ["posthog>=7.5.0",
...] in pyproject.toml conflicts with the version documented in CLAUDE.md (line
91) which requires posthog>=7.6.0; update the pyproject.toml posthog spec to
"posthog>=7.6.0" (or alternatively update CLAUDE.md to 7.5.0) so both sources
reference the same minimum version, and run dependency resolution/tests to
confirm compatibility.

In `@src/github_standup_agent/instrumentation.py`:
- Around line 67-76: shutdown_posthog currently clears _posthog_client but does
not reset the module-level flag _instrumentation_enabled, so is_enabled() can
return True after shutdown; update shutdown_posthog to also set
_instrumentation_enabled = False (referencing the same global as used by
enable/disable functions) inside the function (ensure you declare it global if
needed) so the module state accurately reflects that instrumentation is disabled
after shutdown.

In `@src/github_standup_agent/runner.py`:
- Around line 53-54: The code calls setup_posthog(distinct_id=github_username)
but never calls shutdown_posthog(), so buffered PostHog events may not be
flushed; fix by invoking shutdown_posthog() at the end of each workflow where
setup_posthog() is used (e.g., at the end of the runner functions that
initialize PostHog) or alternatively register atexit handler inside the
instrumentation module (in the setup_posthog implementation) to call
shutdown_posthog() on process exit; locate the setup_posthog and add matching
shutdown_posthog calls or add an atexit.register(shutdown_posthog) in the
instrumentation setup.
🧹 Nitpick comments (1)
CLAUDE.md (1)

82-94: Consider documenting the debug mode.

Based on the AI summary, instrumentation.py supports a POSTHOG_DEBUG environment variable for debug logging. Consider adding this to the documentation for completeness:

 - `POSTHOG_API_KEY` - Enables PostHog agent tracing when set
 - `POSTHOG_HOST` - PostHog host (default: https://us.posthog.com)
 - `POSTHOG_DISTINCT_ID` - User identifier (defaults to github_username)
+- `POSTHOG_DEBUG` - Enable debug logging for PostHog (optional)
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7091d2c and 7a2d0eb.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (6)
  • .env.example
  • CLAUDE.md
  • pyproject.toml
  • src/github_standup_agent/cli.py
  • src/github_standup_agent/instrumentation.py
  • src/github_standup_agent/runner.py
🔇 Additional comments (8)
pyproject.toml (1)

28-28: LGTM!

Adding python-dotenv as a runtime dependency is appropriate since the CLI relies on it to load environment variables early in the startup process.

src/github_standup_agent/cli.py (1)

7-14: Unconventional but intentional import ordering.

Calling load_dotenv() between imports violates PEP 8 ordering but is necessary here to ensure environment variables are available before other modules (like instrumentation.py) read them at import time. The explanatory comment helps clarify this intent.

Consider adding a # noqa: E402 comment on line 14 if linters flag the import ordering, or suppress at the file level if needed.

.env.example (1)

11-16: LGTM!

Clear documentation of the optional PostHog environment variables with appropriate comments indicating they are opt-in.

src/github_standup_agent/runner.py (2)

14-14: Verify the instrumentation module implementation and PostHog lifecycle management.

Ensure the instrumentation.py module:

  1. Implements idempotent setup (safe to call multiple times on lines 53-54 and 147-148 in runner.py)
  2. Handles graceful degradation if the posthog package is not installed
  3. Includes proper error handling if PostHog initialization fails
  4. Provides a shutdown_posthog() function for cleanup on application exit (currently no shutdown calls detected in runner.py)

Additionally, review the trace_include_sensitive_data=True configuration on lines 79 and 159 to ensure sensitive user inputs and GitHub data are not inadvertently exposed in PostHog traces.


77-80: Evaluate the security implications of trace_include_sensitive_data=True.

This setting will include LLM inputs/outputs and tool call payloads in traces. Depending on where traces are sent (PostHog, APM, logging systems, etc.), this could expose sensitive data including GitHub usernames, PR/issue content, and user inputs.

Confirm:

  1. Where traces are being routed (PostHog, APM, etc.)
  2. Whether this aligns with your privacy policy and data handling requirements
  3. Whether a separate opt-in environment variable should control this behavior, rather than being enabled by default
src/github_standup_agent/instrumentation.py (3)

1-10: LGTM!

Module setup with lazy optional dependency pattern is appropriate. The Any type for the optional client and module-level debug flag evaluation are reasonable choices.


79-81: LGTM!

Simple and clear accessor function.


46-51: Verify that privacy_mode=False aligns with data handling requirements.

With privacy_mode=False, LLM inputs and outputs (including user prompts and generated content) will be sent to PostHog. This may include sensitive information depending on usage. Consider:

  1. Documenting this behavior clearly for users enabling PostHog instrumentation.
  2. Offering a POSTHOG_PRIVACY_MODE environment variable to let users opt into privacy mode.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines +40 to +42
posthog = [
"posthog>=7.5.0", # For local dev with openai_agents, install ../posthog-python
]
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Version mismatch with documentation.

The optional dependency specifies posthog>=7.5.0, but CLAUDE.md (line 91) documents posthog>=7.6.0. Align the versions to avoid confusion.

🤖 Prompt for AI Agents
In `@pyproject.toml` around lines 40 - 42, The optional dependency entry posthog =
["posthog>=7.5.0", ...] in pyproject.toml conflicts with the version documented
in CLAUDE.md (line 91) which requires posthog>=7.6.0; update the pyproject.toml
posthog spec to "posthog>=7.6.0" (or alternatively update CLAUDE.md to 7.5.0) so
both sources reference the same minimum version, and run dependency
resolution/tests to confirm compatibility.

Comment on lines +67 to +76
def shutdown_posthog() -> None:
"""Flush and shutdown PostHog client."""
global _posthog_client
if _posthog_client:
try:
_posthog_client.flush()
_posthog_client.shutdown()
except Exception:
pass
_posthog_client = None
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Reset _instrumentation_enabled flag on shutdown.

After shutdown_posthog() is called, is_enabled() will still return True because _instrumentation_enabled is never reset. This creates inconsistent state where the module reports instrumentation as enabled when the client has been shut down.

Proposed fix
 def shutdown_posthog() -> None:
     """Flush and shutdown PostHog client."""
-    global _posthog_client
+    global _posthog_client, _instrumentation_enabled
     if _posthog_client:
         try:
             _posthog_client.flush()
             _posthog_client.shutdown()
         except Exception:
             pass
         _posthog_client = None
+    _instrumentation_enabled = False
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def shutdown_posthog() -> None:
"""Flush and shutdown PostHog client."""
global _posthog_client
if _posthog_client:
try:
_posthog_client.flush()
_posthog_client.shutdown()
except Exception:
pass
_posthog_client = None
def shutdown_posthog() -> None:
"""Flush and shutdown PostHog client."""
global _posthog_client, _instrumentation_enabled
if _posthog_client:
try:
_posthog_client.flush()
_posthog_client.shutdown()
except Exception:
pass
_posthog_client = None
_instrumentation_enabled = False
🤖 Prompt for AI Agents
In `@src/github_standup_agent/instrumentation.py` around lines 67 - 76,
shutdown_posthog currently clears _posthog_client but does not reset the
module-level flag _instrumentation_enabled, so is_enabled() can return True
after shutdown; update shutdown_posthog to also set _instrumentation_enabled =
False (referencing the same global as used by enable/disable functions) inside
the function (ensure you declare it global if needed) so the module state
accurately reflects that instrumentation is disabled after shutdown.

Comment on lines +53 to +54
# Initialize PostHog instrumentation (if configured)
setup_posthog(distinct_id=github_username)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Missing cleanup/shutdown for PostHog.

setup_posthog() is called in both workflows, but there's no corresponding shutdown_posthog() call. According to the AI summary, the instrumentation module provides this function. Without proper shutdown, buffered events may not be flushed before the process exits.

Consider adding cleanup at the end of each workflow or registering an atexit handler in the instrumentation module.

Also applies to: 147-148

🤖 Prompt for AI Agents
In `@src/github_standup_agent/runner.py` around lines 53 - 54, The code calls
setup_posthog(distinct_id=github_username) but never calls shutdown_posthog(),
so buffered PostHog events may not be flushed; fix by invoking
shutdown_posthog() at the end of each workflow where setup_posthog() is used
(e.g., at the end of the runner functions that initialize PostHog) or
alternatively register atexit handler inside the instrumentation module (in the
setup_posthog implementation) to call shutdown_posthog() on process exit; locate
the setup_posthog and add matching shutdown_posthog calls or add an
atexit.register(shutdown_posthog) in the instrumentation setup.

@andrewm4894 andrewm4894 merged commit ac2a807 into main Jan 16, 2026
2 of 4 checks passed
@andrewm4894 andrewm4894 deleted the feat/add-posthog-instrumentation branch January 16, 2026 09:00
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.

2 participants