Capture Claude Code sessions when `SessionEnd` doesn't fire (orchestrated / sandboxed runs)
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 84
- Forks
- 15
- Avg merge
- 14h 34m
- Merged PRs (30d)
- 7
Description
Capture Claude Code sessions when SessionEnd doesn't fire (orchestrated / sandboxed runs)
Hi 👋 — thanks for the plugin, LLMA capture has been really useful and the code is a pleasure to read through.
We're running Claude Code inside ephemeral Daytona sandboxes via sandbox-agent, which launches Claude through the claude-agent-acp adapter. In that setup the LLMA SessionEnd hook never fires — the sandbox is destroyed when the task completes (effectively SIGKILL), and the documented SessionEnd matchers (clear | resume | logout | prompt_input_exit | bypass_permissions_disabled | other, per the hooks docs) don't obviously cover an ACP session closing either. Result: zero capture, silently — session-end-llma.py does sys.exit(0) on any error / early return (a very reasonable "never break the user's workflow" choice!), so it's easy to think it's working when it isn't.
We confirmed the sender itself is fine: running the same JSONL through ${CLAUDE_PLUGIN_ROOT}/hooks/session-end-llma.py manually (piping {"session_id": ..., "cwd": ...} on stdin) cleanly delivers full capture — ~160 events in our case, generations + tool spans + traces, parser handles the still-growing JSONL gracefully. So the data is on disk and the path works; there just isn't an orchestrator-friendly way to trigger it.
Proposal: an opt-in Stop-hook flush mode
What would unblock us — and feels like a good default for autonomous / orchestrated agent setups generally — is an optional incremental-flush mode gated by an env var:
POSTHOG_LLMA_FLUSH_ON=session_end # current behavior, default
POSTHOG_LLMA_FLUSH_ON=stop # flush on every Stop hook (per turn)
This pairs naturally with POSTHOG_LLMA_TRACE_GROUPING=message: each user prompt → one trace → one flush boundary, which gives a clean de-dup story (only emit events whose prompt_id matches the just-finished turn). The orchestrator survives the host killing the process between turns without losing anything.
A doc-only alternative would also help our specific case — just blessing "pipe {session_id, cwd} into hooks/session-end-llma.py from your orchestrator" in the README — though it leaves the silent-failure mode in place for everyone else.
Happy to send a PR; mostly wanted to surface the case and hear how you'd prefer to shape it.
Environment
- Plugin
posthogv1.1.21 viaclaude-plugins-official(sourcePostHog/ai-plugin@ff08c376) - Claude Code on macOS for local testing; Daytona sandbox via
claude-agent-acpfor the orchestrated path - PostHog Cloud, EU region
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with hooks/session-end-llma.py and the Claude Code hook configuration, then trace how SessionEnd currently supplies session_id and cwd. Check the Stop-hook behavior and the POSTHOG_LLMA_FLUSH_ON and POSTHOG_LLMA_TRACE_GROUPING options; done means an opt-in stop mode flushes completed turns while session_end remains the default.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- ai, tooling
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100