Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 138 additions & 0 deletions .agents/skills/posthog-cli-queries/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
---
name: posthog-cli-queries
description: Use when querying this project's PostHog data from the terminal, including recent events, event breakdowns, active-user metrics, and dashboard metadata or cached insight results.
---

# PostHog CLI Queries

Query this project's PostHog data from the terminal without guessing command syntax.

## When To Use

- The user asks to inspect PostHog events, trends, or dashboard data
- The task needs real data from this project's PostHog environment
- The user wants a repeatable terminal command instead of clicking in the PostHog UI

Comment thread
debugtheworldbot marked this conversation as resolved.
## Preconditions

- `posthog-cli` must be installed and authenticated
- Query commands need a personal API key with `query:read`
- Dashboard API helpers read `~/.posthog/credentials.json`
- This project currently uses PostHog environment `292804` on `https://us.posthog.com`, but scripts read the active local credentials instead of hardcoding values

## Default Workflow

1. Verify auth:

```bash
posthog-cli exp query run 'SELECT 1 AS ok'
```

2. For event data, use `posthog-cli exp query run '<hogql>'`
3. For dashboard metadata or cached dashboard insight results, use the scripts in this skill because the CLI has no dedicated dashboard command
4. Return:
- the exact command used
- the key rows or aggregates
- any metric caveats such as partial-day data, test-account filtering, or missing properties

Shell quoting rule:

- Use single quotes around HogQL when the query contains properties like `$app_version` or `$os`, otherwise the shell may expand them before the CLI sees the query

## Common Queries

Recent events:

```bash
posthog-cli exp query run 'SELECT event, timestamp FROM events ORDER BY timestamp DESC LIMIT 20'
```

Top events in the last 7 days:

```bash
posthog-cli exp query run 'SELECT event, count() AS c FROM events WHERE timestamp > now() - INTERVAL 7 DAY GROUP BY event ORDER BY c DESC LIMIT 15'
```

Top `pageview` pages in the last 7 days:

```bash
posthog-cli exp query run "SELECT properties.page_name AS page_name, count() AS c FROM events WHERE event = 'pageview' AND timestamp > now() - INTERVAL 7 DAY GROUP BY page_name ORDER BY c DESC LIMIT 15"
```

Top `click` targets in the last 7 days:

```bash
posthog-cli exp query run "SELECT properties.element_name AS element_name, count() AS c FROM events WHERE event = 'click' AND timestamp > now() - INTERVAL 7 DAY GROUP BY element_name ORDER BY c DESC LIMIT 15"
```

Recent app versions from events:

```bash
posthog-cli exp query run 'SELECT properties.$app_version AS app_version, count() AS c FROM events WHERE timestamp > now() - INTERVAL 7 DAY GROUP BY app_version ORDER BY c DESC LIMIT 20'
```

Recent OS breakdown:

```bash
posthog-cli exp query run 'SELECT properties.$os AS os, count(DISTINCT person_id) AS users FROM events WHERE timestamp > now() - INTERVAL 7 DAY GROUP BY os ORDER BY users DESC LIMIT 20'
```

Hourly volume in the last 24 hours:

```bash
posthog-cli exp query run 'SELECT toStartOfHour(timestamp) AS hour, count() AS c FROM events WHERE timestamp > now() - INTERVAL 24 HOUR GROUP BY hour ORDER BY hour DESC LIMIT 24'
```

## Dashboard Commands

List dashboards:

```bash
bash .agents/skills/posthog-cli-queries/scripts/dashboard_list.sh
```

Fetch a dashboard as JSON:

```bash
bash .agents/skills/posthog-cli-queries/scripts/dashboard_fetch.sh 1075953
```

Fetch a dashboard summary:

```bash
bash .agents/skills/posthog-cli-queries/scripts/dashboard_fetch.sh 1075953 --summary
```

Current known dashboard:

```bash
bash .agents/skills/posthog-cli-queries/scripts/dashboard_fetch.sh 1075953 --summary
```

## Dashboard Analysis Notes

- Dashboard results are usually cached insight payloads, so `last_refresh` matters
- Do not compare a partial current day against a full previous day without saying so explicitly
- Check `filterTestAccounts` before comparing tiles with each other
- If `$os` or `$app_version` has a large `null` bucket, call out that the property coverage is incomplete
- If event names overlap like `app_open` and `Application Opened`, mention that the taxonomy is split

## Useful jq Snippets

Extract tile names from a fetched dashboard JSON:

```bash
jq -r '.tiles[] | select(.insight != null) | [.id, .insight.id, .insight.name] | @tsv'
```

Show top breakdown rows from one insight result:

```bash
jq -r '.tiles[] | select(.insight.id==6334935) | .insight.result[] | [.label, .count, (.data[-1] // 0)] | @tsv'
```

## Failure Handling

- If `posthog-cli exp query run` says `missing required scope 'query:read'`, fix the personal API key scopes first
- If a query times out, narrow the date range or aggregate more aggressively
- If dashboard scripts fail, confirm `~/.posthog/credentials.json` exists and contains `host`, `token`, and `env_id`
57 changes: 57 additions & 0 deletions .agents/skills/posthog-cli-queries/scripts/dashboard_fetch.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/usr/bin/env bash
set -euo pipefail

if [[ $# -lt 1 ]]; then
echo "Usage: $0 <dashboard_id> [--summary]" >&2
exit 1
fi

dashboard_id="$1"
mode="${2:-}"
cred_file="${HOME}/.posthog/credentials.json"

if [[ ! -f "${cred_file}" ]]; then
echo "Missing credentials file: ${cred_file}" >&2
exit 1
fi

token="$(jq -r '.token // empty' "${cred_file}")"
host="$(jq -r '.host // empty' "${cred_file}")"

if [[ -z "${token}" || -z "${host}" ]]; then
echo "Expected host and token in ${cred_file}" >&2
exit 1
fi

response="$(
curl -fsS \
-H "Authorization: Bearer ${token}" \
Comment on lines +26 to +28
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

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

This script passes the PostHog API token directly on the curl command line via -H "Authorization: Bearer ...", which can be exposed to other local users via process listings. Consider supplying headers via a temporary config/header file (e.g., curl --config / -H @file) or another mechanism that doesn’t put the token in argv.

Suggested change
response="$(
curl -fsS \
-H "Authorization: Bearer ${token}" \
header_file="$(mktemp)"
chmod 600 "${header_file}"
trap 'rm -f "${header_file}"' EXIT
printf 'Authorization: Bearer %s\n' "${token}" > "${header_file}"
response="$(
curl -fsS \
-H @"${header_file}" \

Copilot uses AI. Check for mistakes.
"${host%/}/api/dashboard/${dashboard_id}"
)"

if [[ "${mode}" == "--summary" ]]; then
jq -r '
"Dashboard\t" + (.id | tostring) + "\t" + .name,
(
.tiles[]
| select(.insight != null)
| [
(.id | tostring),
(.insight.id | tostring),
(
if (.insight.name // "") != "" then .insight.name
elif (.insight.derived_name // "") != "" then .insight.derived_name
else (.insight.short_id // "")
end
),
(.insight.query.source.kind // ""),
(.insight.query.source.interval // ""),
((.insight.result // [] | length) | tostring),
(.last_refresh // .insight.last_refresh // "")
]
| @tsv
)
' <<<"${response}"
else
jq '.' <<<"${response}"
fi
31 changes: 31 additions & 0 deletions .agents/skills/posthog-cli-queries/scripts/dashboard_list.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#!/usr/bin/env bash
set -euo pipefail

cred_file="${HOME}/.posthog/credentials.json"

if [[ ! -f "${cred_file}" ]]; then
echo "Missing credentials file: ${cred_file}" >&2
exit 1
fi

token="$(jq -r '.token // empty' "${cred_file}")"
host="$(jq -r '.host // empty' "${cred_file}")"
env_id="$(jq -r '.env_id // empty' "${cred_file}")"

if [[ -z "${token}" || -z "${host}" || -z "${env_id}" ]]; then
echo "Expected host, token, and env_id in ${cred_file}" >&2
exit 1
fi

curl -fsS \
-H "Authorization: Bearer ${token}" \
Comment on lines +20 to +21
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

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

This script passes the PostHog API token directly on the curl command line via -H "Authorization: Bearer ...", which can be exposed to other local users via process listings. Consider supplying headers via a temporary config/header file (e.g., curl --config / -H @file) or another mechanism that doesn’t put the token in argv.

Suggested change
curl -fsS \
-H "Authorization: Bearer ${token}" \
header_file="$(mktemp)"
trap 'rm -f "${header_file}"' EXIT
chmod 600 "${header_file}"
printf 'Authorization: Bearer %s\n' "${token}" > "${header_file}"
curl -fsS \
-H @"${header_file}" \

Copilot uses AI. Check for mistakes.
"${host%/}/api/dashboard/" |
jq -r --arg env_id "${env_id}" '
if (.results | length) == 0 then
"No dashboards found for environment \($env_id)"
else
.results[]
| [.id, .name, (.pinned // false), (.last_accessed_at // ""), (.last_viewed_at // "")]
| @tsv
end
'
Loading