Skip to content

docs(llma): add Claude Agent SDK installation onboarding content#53011

Merged
andrewm4894 merged 3 commits into
masterfrom
docs/llma-claude-agent-sdk-installation
Apr 21, 2026
Merged

docs(llma): add Claude Agent SDK installation onboarding content#53011
andrewm4894 merged 3 commits into
masterfrom
docs/llma-claude-agent-sdk-installation

Conversation

@andrewm4894
Copy link
Copy Markdown
Member

Problem

No installation docs for the new Claude Agent SDK integration in LLM Analytics.

Changes

Adds docs/onboarding/llm-analytics/claude-agent-sdk.tsx — shared onboarding content covering:

  • Installing PostHog + Claude Agent SDK
  • query() drop-in replacement
  • instrument() reusable configuration
  • Multi-turn tool usage examples

Companion PR in posthog.com adds the MDX wrapper and nav entry.

Part of #53010. Depends on PostHog/posthog-python#477.

How did you test this code?

Content follows the exact same pattern as openai-agents.tsx. Will render once both this PR and the posthog.com PR are merged.

Publish to changelog?

No

Adds the shared onboarding TSX for the Claude Agent SDK integration.
Covers query() drop-in, instrument() reuse, and multi-turn tool usage.

Part of #53010.
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 1, 2026

Prompt To Fix All With AI
This is a comment left during a code review.
Path: docs/onboarding/llm-analytics/claude-agent-sdk.tsx
Line: 144-160

Comment:
**`async for` used outside async context — snippet won't run**

The `async for` loops at the end of this block are at module/top-level without being wrapped in an `async def` and `asyncio.run()`. Python will raise a `SyntaxError` for this in any normal script. Compare with step 3, which correctly wraps everything in `async def main()` and calls `asyncio.run(main())`.

```suggestion
                    <CodeBlock
                        language="python"
                        code={dedent`
                            import asyncio
                            from posthog import Posthog
                            from posthog.ai.claude_agent_sdk import instrument
                            from claude_agent_sdk import ClaudeAgentOptions

                            posthog = Posthog(
                                "<ph_project_token>",
                                host="<ph_client_api_host>"
                            )

                            ph = instrument(
                                client=posthog,
                                distinct_id="user_123",
                                properties={"app": "my-agent"},
                            )

                            options = ClaudeAgentOptions(max_turns=10)

                            async def main():
                                # All queries share the same PostHog config
                                async for msg in ph.query(prompt="Question 1", options=options):
                                    ...
                                async for msg in ph.query(prompt="Question 2", options=options):
                                    ...

                            asyncio.run(main())
                            posthog.shutdown()
                        `}
                    />
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: docs/onboarding/llm-analytics/claude-agent-sdk.tsx
Line: 181-222

Comment:
**Incomplete imports and missing `asyncio` wrapper in tool-usage example**

This code block has three problems that would prevent it from working as a standalone script:

1. `query` is used but never imported in this block (it was imported in step 3, but each code block should be self-contained or clearly note the dependency).
2. `posthog` is referenced but not initialized anywhere in this block.
3. `async for` at module level is a `SyntaxError` outside an `async def`/`asyncio.run()`.

A self-contained, runnable snippet would look like:

```python
import asyncio
from posthog import Posthog
from posthog.ai.claude_agent_sdk import query
from claude_agent_sdk import ClaudeAgentOptions, AssistantMessage, TextBlock, ToolUseBlock

posthog = Posthog("<ph_project_token>", host="<ph_client_api_host>")

options = ClaudeAgentOptions(
    max_turns=10,
    allowed_tools=["Read", "Glob", "Grep", "Bash"],
    permission_mode="bypassPermissions",
    cwd="/path/to/your/project",
)

async def main():
    async for message in query(
        prompt="Read the README and summarize this project",
        options=options,
        posthog_client=posthog,
        posthog_distinct_id="user_123",
    ):
        if isinstance(message, AssistantMessage):
            for block in message.content:
                if isinstance(block, TextBlock):
                    print(block.text)
                elif isinstance(block, ToolUseBlock):
                    print(f"Tool: {block.name}")

asyncio.run(main())
posthog.shutdown()
```

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "docs(llma): add Claude Agent SDK install..." | Re-trigger Greptile

Comment on lines +144 to +160
)

ph = instrument(
client=posthog,
distinct_id="user_123",
properties={"app": "my-agent"},
)

options = ClaudeAgentOptions(max_turns=10)

# All queries share the same PostHog config
async for msg in ph.query(prompt="Question 1", options=options):
...
async for msg in ph.query(prompt="Question 2", options=options):
...
`}
/>
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.

P1 async for used outside async context — snippet won't run

The async for loops at the end of this block are at module/top-level without being wrapped in an async def and asyncio.run(). Python will raise a SyntaxError for this in any normal script. Compare with step 3, which correctly wraps everything in async def main() and calls asyncio.run(main()).

Suggested change
)
ph = instrument(
client=posthog,
distinct_id="user_123",
properties={"app": "my-agent"},
)
options = ClaudeAgentOptions(max_turns=10)
# All queries share the same PostHog config
async for msg in ph.query(prompt="Question 1", options=options):
...
async for msg in ph.query(prompt="Question 2", options=options):
...
`}
/>
<CodeBlock
language="python"
code={dedent`
import asyncio
from posthog import Posthog
from posthog.ai.claude_agent_sdk import instrument
from claude_agent_sdk import ClaudeAgentOptions
posthog = Posthog(
"<ph_project_token>",
host="<ph_client_api_host>"
)
ph = instrument(
client=posthog,
distinct_id="user_123",
properties={"app": "my-agent"},
)
options = ClaudeAgentOptions(max_turns=10)
async def main():
# All queries share the same PostHog config
async for msg in ph.query(prompt="Question 1", options=options):
...
async for msg in ph.query(prompt="Question 2", options=options):
...
asyncio.run(main())
posthog.shutdown()
`}
/>
Prompt To Fix With AI
This is a comment left during a code review.
Path: docs/onboarding/llm-analytics/claude-agent-sdk.tsx
Line: 144-160

Comment:
**`async for` used outside async context — snippet won't run**

The `async for` loops at the end of this block are at module/top-level without being wrapped in an `async def` and `asyncio.run()`. Python will raise a `SyntaxError` for this in any normal script. Compare with step 3, which correctly wraps everything in `async def main()` and calls `asyncio.run(main())`.

```suggestion
                    <CodeBlock
                        language="python"
                        code={dedent`
                            import asyncio
                            from posthog import Posthog
                            from posthog.ai.claude_agent_sdk import instrument
                            from claude_agent_sdk import ClaudeAgentOptions

                            posthog = Posthog(
                                "<ph_project_token>",
                                host="<ph_client_api_host>"
                            )

                            ph = instrument(
                                client=posthog,
                                distinct_id="user_123",
                                properties={"app": "my-agent"},
                            )

                            options = ClaudeAgentOptions(max_turns=10)

                            async def main():
                                # All queries share the same PostHog config
                                async for msg in ph.query(prompt="Question 1", options=options):
                                    ...
                                async for msg in ph.query(prompt="Question 2", options=options):
                                    ...

                            asyncio.run(main())
                            posthog.shutdown()
                        `}
                    />
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +181 to +222
title: 'Tool usage and multi-turn conversations',
badge: 'optional',
content: (
<>
<Markdown>
PostHog captures the full trace hierarchy for multi-turn agent conversations with tool calls.
Each tool use is captured as an `$ai_span` event linked to its parent generation.
</Markdown>

<CodeBlock
language="python"
code={dedent`
from claude_agent_sdk import ClaudeAgentOptions, AssistantMessage, TextBlock, ToolUseBlock

options = ClaudeAgentOptions(
max_turns=10,
allowed_tools=["Read", "Glob", "Grep", "Bash"],
permission_mode="bypassPermissions",
cwd="/path/to/your/project",
)

async for message in query(
prompt="Read the README and summarize this project",
options=options,
posthog_client=posthog,
posthog_distinct_id="user_123",
):
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
print(block.text)
elif isinstance(block, ToolUseBlock):
print(f"Tool: {block.name}")
`}
/>

<Markdown>
{dedent`
This captures:
- \`$ai_generation\` events for each LLM turn (with token counts, cost, and cache metrics)
- \`$ai_span\` events for each tool use (Read, Glob, Grep, Bash, etc.)
- An \`$ai_trace\` event grouping the entire conversation with total cost and latency
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.

P1 Incomplete imports and missing asyncio wrapper in tool-usage example

This code block has three problems that would prevent it from working as a standalone script:

  1. query is used but never imported in this block (it was imported in step 3, but each code block should be self-contained or clearly note the dependency).
  2. posthog is referenced but not initialized anywhere in this block.
  3. async for at module level is a SyntaxError outside an async def/asyncio.run().

A self-contained, runnable snippet would look like:

import asyncio
from posthog import Posthog
from posthog.ai.claude_agent_sdk import query
from claude_agent_sdk import ClaudeAgentOptions, AssistantMessage, TextBlock, ToolUseBlock

posthog = Posthog("<ph_project_token>", host="<ph_client_api_host>")

options = ClaudeAgentOptions(
    max_turns=10,
    allowed_tools=["Read", "Glob", "Grep", "Bash"],
    permission_mode="bypassPermissions",
    cwd="/path/to/your/project",
)

async def main():
    async for message in query(
        prompt="Read the README and summarize this project",
        options=options,
        posthog_client=posthog,
        posthog_distinct_id="user_123",
    ):
        if isinstance(message, AssistantMessage):
            for block in message.content:
                if isinstance(block, TextBlock):
                    print(block.text)
                elif isinstance(block, ToolUseBlock):
                    print(f"Tool: {block.name}")

asyncio.run(main())
posthog.shutdown()
Prompt To Fix With AI
This is a comment left during a code review.
Path: docs/onboarding/llm-analytics/claude-agent-sdk.tsx
Line: 181-222

Comment:
**Incomplete imports and missing `asyncio` wrapper in tool-usage example**

This code block has three problems that would prevent it from working as a standalone script:

1. `query` is used but never imported in this block (it was imported in step 3, but each code block should be self-contained or clearly note the dependency).
2. `posthog` is referenced but not initialized anywhere in this block.
3. `async for` at module level is a `SyntaxError` outside an `async def`/`asyncio.run()`.

A self-contained, runnable snippet would look like:

```python
import asyncio
from posthog import Posthog
from posthog.ai.claude_agent_sdk import query
from claude_agent_sdk import ClaudeAgentOptions, AssistantMessage, TextBlock, ToolUseBlock

posthog = Posthog("<ph_project_token>", host="<ph_client_api_host>")

options = ClaudeAgentOptions(
    max_turns=10,
    allowed_tools=["Read", "Glob", "Grep", "Bash"],
    permission_mode="bypassPermissions",
    cwd="/path/to/your/project",
)

async def main():
    async for message in query(
        prompt="Read the README and summarize this project",
        options=options,
        posthog_client=posthog,
        posthog_distinct_id="user_123",
    ):
        if isinstance(message, AssistantMessage):
            for block in message.content:
                if isinstance(block, TextBlock):
                    print(block.text)
                elif isinstance(block, ToolUseBlock):
                    print(f"Tool: {block.name}")

asyncio.run(main())
posthog.shutdown()
```

How can I resolve this? If you propose a fix, please make it concise.

Comment thread docs/onboarding/llm-analytics/claude-agent-sdk.tsx Outdated
Comment thread docs/onboarding/llm-analytics/claude-agent-sdk.tsx Outdated
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 9, 2026

This PR hasn't seen activity in a week! Should it be merged, closed, or further worked on? If you want to keep it open, please remove the stale label – otherwise this will be closed in another week. If you want to permanently keep it open, use the waiting label.

@github-actions github-actions Bot added the stale label Apr 9, 2026
@andrewm4894 andrewm4894 added stamphog Request AI review from stamphog and removed stale labels Apr 10, 2026
Copy link
Copy Markdown

@stamphog stamphog Bot left a comment

Choose a reason for hiding this comment

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

The documentation code snippets contain real Python errors that bot reviewers flagged and remain unaddressed: the "Reusable configuration with instrument()" step has async for loops at module level (a SyntaxError in Python), and the "Tool usage and multi-turn conversations" step uses query and posthog without importing or initializing them. These are legitimate issues in user-facing documentation that would mislead developers.

@stamphog stamphog Bot removed the stamphog Request AI review from stamphog label Apr 10, 2026
@github-actions
Copy link
Copy Markdown
Contributor

Docs from this PR will be published at posthog.com

Project Deployment Preview Updated (UTC)
posthog.com 🤷 Unknown Preview Apr 10, 2026, 10:11 AM

Preview will be ready in ~10 minutes. Click Preview link above to access docs at /handbook/engineering/

@andrewm4894 andrewm4894 added the stamphog Request AI review from stamphog label Apr 10, 2026
Copy link
Copy Markdown

@stamphog stamphog Bot left a comment

Choose a reason for hiding this comment

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

The previously bot-flagged Python syntax errors in Steps 4 and 5 were fixed, but the new Step 6 ("Multi-turn conversations with history") introduces the same class of error: async with, await, and async for are used at module level without an enclosing async def / asyncio.run() wrapper, which is a SyntaxError in any standard Python script and directly misleads users copying this user-facing documentation snippet.

@stamphog stamphog Bot removed the stamphog Request AI review from stamphog label Apr 10, 2026
Comment on lines +162 to +163
asyncio.run(main())
`}
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.

Consistency issue: Missing posthog.shutdown() call after asyncio.run(main()). This is inconsistent with the examples in steps 3 and 5 (lines 100 and 229) which both include the shutdown call. Without it, the PostHog client may not flush pending events before the program exits.

asyncio.run(main())
posthog.shutdown()
Suggested change
asyncio.run(main())
`}
asyncio.run(main())
posthog.shutdown()
`}

Spotted by Graphite

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

@github-actions
Copy link
Copy Markdown
Contributor

This PR hasn't seen activity in a week! Should it be merged, closed, or further worked on? If you want to keep it open, please remove the stale label – otherwise this will be closed in another week. If you want to permanently keep it open, use the waiting label.

@github-actions github-actions Bot added the stale label Apr 20, 2026
@andrewm4894 andrewm4894 requested a review from a team April 21, 2026 19:46
@andrewm4894 andrewm4894 added the stamphog Request AI review from stamphog label Apr 21, 2026
Copy link
Copy Markdown

@stamphog stamphog Bot left a comment

Choose a reason for hiding this comment

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

Step 6 of the documentation contains a genuine Python SyntaxError: async with, await, and async for are used at module level without an enclosing async def / asyncio.run() wrapper. This directly misleads users copying the snippet. The bot reviewer flagged this on the current head and it remains unaddressed.

@stamphog stamphog Bot removed the stamphog Request AI review from stamphog label Apr 21, 2026
@andrewm4894 andrewm4894 merged commit 0a0ee15 into master Apr 21, 2026
186 checks passed
@andrewm4894 andrewm4894 deleted the docs/llma-claude-agent-sdk-installation branch April 21, 2026 19:56
inkeep Bot added a commit to PostHog/posthog.com that referenced this pull request Apr 21, 2026
Companion page for PostHog/posthog#53011 which added the shared
onboarding content at docs/onboarding/llm-analytics/claude-agent-sdk.tsx.

Follows the same pattern as openai-agents.mdx — imports the shared
component and wraps it with OnboardingContentWrapper and addNextStepsStep.
@deployment-status-posthog
Copy link
Copy Markdown

deployment-status-posthog Bot commented Apr 21, 2026

Deploy status

Environment Status Deployed At Workflow
dev ✅ Deployed 2026-04-21 20:22 UTC Run
prod-us ✅ Deployed 2026-04-21 20:32 UTC Run
prod-eu ✅ Deployed 2026-04-21 20:34 UTC Run

andrewm4894 pushed a commit to PostHog/posthog.com that referenced this pull request Apr 22, 2026
Companion page for PostHog/posthog#53011 which added the shared
onboarding content at docs/onboarding/llm-analytics/claude-agent-sdk.tsx.

Follows the same pattern as openai-agents.mdx — imports the shared
component and wraps it with OnboardingContentWrapper and addNextStepsStep.

Co-authored-by: inkeep[bot] <257615677+inkeep[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants