
Debugging Local Task Runs
FreeEfficiently debug PostHog task runs in local Docker environments.
Free · Opens the source repo
What Debugging Local Task Runs does
Debugging local task runs for PostHog can be challenging, particularly when using the Temporal workflow system. This skill provides a streamlined approach to access and analyze the output of local task runs executed within a Docker sandbox. It is specifically designed for developers working with PostHog's Tasks product, enabling them to troubleshoot issues effectively when a local run appears stuck, fails, or produces no output.
The skill facilitates the retrieval of crucial information such as the task UUID and run UUID, which are essential for accessing logs and understanding the state of the task. With commands to find these UUIDs, users can quickly identify the relevant Docker container and begin monitoring the logs in real-time. The skill also details how to read both live logs during execution and durable logs stored in object storage after the task has completed, ensuring that no vital information is lost.
For developers who need to debug integrations with PostHog, this skill covers the necessary environment configurations, including .env.local keys, to ensure that local cloud runs operate correctly. It also addresses the limitations of the Temporal UI, which does not display the output of tasks, thus making this skill an essential tool for anyone working within this ecosystem. By following the structured steps provided, users can efficiently navigate the debugging process and resolve issues more effectively.
Overall, this skill is a practical resource for developers who need to ensure that their local task runs are functioning correctly and who require access to detailed logs for troubleshooting purposes. It is particularly beneficial for those integrating PostHog with their coding agents, as it simplifies the debugging process and enhances productivity.
When to use it
Use this skill when you need to troubleshoot local task runs in PostHog and need access to detailed logs and UUIDs.
When not to use it
This skill is not suitable for debugging remote task runs or for users unfamiliar with Docker and Temporal workflows.
What you can build with it
Troubleshooting Stuck Tasks
When a local PostHog task run appears stuck, use this skill to access logs and identify the issue.
Monitoring Live Logs
During a task run, you can tail live logs to monitor the progress of the wizard and agent stages.
Accessing Durable Logs Post-Run
After a task run completes, retrieve the durable logs from object storage for further analysis.
How to install Debugging Local Task Runs
View source1. Install with the skills CLI
npx skills add posthog/posthog/debugging-local-task-agent-runs --agent claude-code2. Or install it manually
Download the skill folder and drop it into ~/.claude/skills/ for all projects, or .claude/skills/ to scope it to one repo. Restart Claude Code so it picks up the new skill.
Anthropic's agentic coding CLI, and the reference implementation of Agent Skills. Drop a skill folder into ~/.claude/skills and Claude Code loads it automatically whenever a task matches the skill's description. Claude Code docs
Inside SKILL.md
Written by posthogDebugging local task/agent runs
A "cloud run" of the Tasks product (e.g. the setup-wizard cloud_run endpoint) executes as the Temporal process-task workflow on the development-task-queue. Locally (SANDBOX_PROVIDER=docker) each run gets a Docker sandbox container in which two things happen in sequence:
run_wizardactivity — runs the published@posthog/wizardto integrate PostHog (writes/tmp/posthog-wizard.log).agent-server— the coding agent that commits the wizard's changes, opens the PR, and keeps it green (writes/tmp/agent-server.log).
The hard part of debugging is that the Temporal UI doesn't show this output — workflow result/failure payloads are binary/encrypted, and the activity captures the wizard/agent output to the run's logs, not to the timeline. This skill is how you actually read it.
Prerequisites: env for local cloud runs
Cloud runs only work locally if all of these are set in .env.local (values shown are the local targets — never commit real secrets). Inside the Docker sandbox, localhost is the container itself, so PostHog URLs use host.docker.internal.
| Key | Purpose / local value |
|---|---|
SANDBOX_PROVIDER | "docker" — route sandboxes to local Docker instead of Modal |
SANDBOX_MCP_URL | "http://host.docker.internal:8787/mcp" — MCP server the agent uses |
SANDBOX_LLM_GATEWAY_URL | "http://host.docker.internal:3308" — local LLM gateway the agent routes model calls through |
SANDBOX_JWT_PRIVATE_KEY | signs the scoped sandbox tokens |
GITHUB_APP_CLIENT_ID | your local GitHub App (clone + PR) |
GITHUB_APP_CLIENT_SECRET | "" |
GITHUB_APP_SLUG | "" |
GITHUB_APP_PRIVATE_KEY | "" |
LLM_GATEWAY_ANTHROPIC_API_KEY | real Anthropic key the local gateway proxies to (read via the gateway's LLM_GATEWAY_ env prefix) |
Two non-env requirements, or the keys above are inert:
- The LLM gateway must actually be running on
:3308. It's gated behind thellm_gatewaycapability — enable theai_featuresintent (hogli dev:setup) so thellm-gatewayproc starts.SANDBOX_LLM_GATEWAY_URLpointing at a dead port just yieldsConnectionRefusedfrom the agent. - The wizard OAuth app must exist —
bin/ensure-local-setupprovisions it and setsWIZARD_CLOUD_RUN_OAUTH_CLIENT_ID; without it thecloud_runendpoint returns 404 "not available".
After editing .env.local, restart the stack — env is read at process start, not hot-reloaded.
Step 1 — find the task UUID
You need the task UUID for the container, and sometimes the run UUID for the durable log. The workflow id encodes both: task-processing-<task_id>-<run_id>.
Fastest (no Temporal needed — the sandbox container name carries the task UUID):
docker ps --format '{{.Names}}' | grep task-sandbox
# task-sandbox-<TASK_ID>-<suffix>
From the Temporal CLI (lists running/recent process-task workflows with both UUIDs):
docker exec posthog-temporal-admin-tools-1 \
temporal workflow list --address temporal:7233 --namespace default --limit 10 \
| grep process-task
# task-processing-<TASK_ID>-<RUN_ID> process-task Running
From the Temporal UI — http://localhost:8081, open the process-task workflow; the id in the URL is task-processing-<TASK_ID>-<RUN_ID>.
Step 2 — tail live logs inside the sandbox (while it's running)
The wizard and agent write line-by-line to files in the container as they run, so this is the only way to watch progress live (the activity buffers stdout and only flushes to the durable log when it finishes).
TASK_ID=<task-uuid-from-step-1>
CID=$(docker ps -q --filter "name=task-sandbox-$TASK_ID")
docker exec "$CID" tail -f /tmp/posthog-wizard.log # wizard stage (full agent SDK detail)
docker exec "$CID" tail -f /tmp/agent-server.log # agent stage (commit + PR + CI loop)
Both files are JSON-heavy. For just the readable activity:
docker exec "$CID" tail -f /tmp/agent-server.log \
| grep -iE '"text"|tool_use|error|✔|✖|commit|PR|CI'
These files vanish when the sandbox is torn down (on run completion/failure), so grab them while the container is up.
Step 3 — read the durable per-run console log (after teardown)
Everything the wizard and agent emit is persisted to the run's console log in object storage at tasks/logs/team_<id>/task_<id>/run_<run_id>.jsonl. This survives teardown. Read it with the run UUID (last UUID of the workflow id; or TaskRun.objects.filter(task_id=...).latest("created_at")):
RUN_ID=<run-uuid>
flox activate -- bash -c "python manage.py shell <<'PY'
import json
from products.tasks.backend.models import TaskRun
from posthog.storage import object_storage
tr = TaskRun.objects.get(id='$RUN_ID')
print('status:', tr.status)
for line in (object_storage.read(tr.log_url, missing_ok=True) or '').splitlines():
n = json.loads(line).get('notification', {}); m = n.get('method'); p = n.get('params', {})
if m == '_posthog/console':
print(f\"[{p.get('level')}] {p.get('message','')[:300]}\")
elif m == 'session/update': # the agent stage (ACP stream)
u = p.get('update', {}); t = u.get('sessionUpdate')
if t == 'tool_call': print(' tool→', u.get('title') or u.get('kind'))
elif t == 'tool_call_update' and u.get('status'): print(' tool✓', u.get('status'))
PY"
Notes on what you'll (not) see here:
- Wizard stdout/verbose lands as
_posthog/consoledebug events, but only afterrun_wizardfinishes (bufferedsandbox.execute). Mid-run, use Step 2. - Agent prose is filtered out.
append_logdropsagent_message_chunkevents to keep the log lean, so the durable log shows what the agent did (tool calls, commits, progress) but not its narration. For the agent's reasoning, read/tmp/agent-server.login the container (Step 2) before teardown.
Common failure signatures
Could not determine cloud region from access token— the wizard hit cloud auth instead of your local instance. Local needs the wizard pointed at the local base URL; seerun_wizard._build_wizard_command(--base-url, DEBUG-gated).Unable to connect to API (ConnectionRefused)from the agent —LLM_GATEWAY_URL=UNSETor the gateway isn't on:3308. CheckSANDBOX_LLM_GATEWAY_URL+ theai_featuresintent (gateway proc).- Auth/4xx from the gateway — the gateway is reachable but has no upstream provider key (
LLM_GATEWAY_ANTHROPIC_API_KEY) or the token lacksllm_gateway:read. - Workflow "running" but nothing happening — it's in the wait loop (CI follow-up / inactivity). The workflow's Temporal Current Details field names what it's waiting on.
Frequently asked questions about Debugging Local Task Runs
Similar skills
Agent Host Debug Logs
Analyze Agent Host debug logs for deeper insights.
Code OSS Dev - Launch + Debug
Launch and debug Code OSS with isolated profiles.
Phoenix CLI
Debug LLM applications with structured analysis tools.
Power Automate Debugging
Diagnose and fix Power Automate flow errors effectively.
Arize Trace
Inspect and export traces for LLM applications.
Runtime Behavior Probe
Investigate real runtime behavior with precision.
