posthog-errors
Weekly cross-project error overview from PostHog - enumerates every project the OAuth grant covers, pulls the last 7 days of error-tracking issues per project, ranks them by impact, flags what's new vs ongoing, and sends one digest with per-project totals, the top issues, and a clickable link to a full committed report of every issue.
git clone --depth 1 https://github.com/aeonfun/aeon /tmp/posthog-errors && cp -r /tmp/posthog-errors/skills/posthog-errors ~/.claude/skills/posthog-errorsSKILL.md
Today is ${today}.
> **${var}** — optional scope override. Empty (default) → **all** projects the OAuth
> grant covers, **last 7 days**. Accepts:
> - `Nd` — change the window, e.g. `14d` or `30d` (bare number also read as days).
> - a comma-list of project name substrings — e.g. `web, api` limits to projects
> whose name contains one of those (case-insensitive). Combine with a window:
> `web, api, 14d`.
>
> This runs unattended — treat `${var}` as final, no confirmation step.
Give the operator a single, scannable overview of the errors across **every** one of
their PostHog projects for the past week. The heavy lifting is the **PostHog MCP
server** (`mcp.posthog.com/mcp`): it enumerates the projects and returns the
error-tracking issues, so you reason over structured facts (occurrence counts, users
affected, first/last-seen timestamps) instead of guessing. Your job is to fan out
across projects, rank by impact, separate new from ongoing, and write the digest.
## Capability notes (read before running or editing)
`mode: read-only` is load-bearing and shapes **how** this skill writes. The read-only
toolset (`scripts/skill_mode.sh`) drops `Write`, `Edit`, and `python`; it keeps `Read`,
the MCP tools, `curl`, `jq`, and `Bash` for `node`/`cat`/`echo`/`mkdir`/`date`/`jq`. So
every file this skill produces — the `./notify` body and the state snapshot — is
written with a **`cat` heredoc (or `node`) redirection**, never the Write tool and
never `python`. Reaching for `python` to build or send the digest gets denied mid-run
and the notification silently never ships. `./notify` itself works in read-only, but
its multi-line body must be a file written the way above — and that scratch file goes
under **`/tmp/`**, never `memory/`/`output/` (those are committed; only the Step 4
snapshot and Step 4b report are meant to persist).
## Detection & auth
The server is wired in `.mcp.json` as `posthog` by the dashboard MCP panel's one-click
**Connect** (OAuth 2.1 + PKCE against `oauth.posthog.com`; tokens stored as
`MCP_POSTHOG_TOKEN` + `MCP_POSTHOG_OAUTH`, and a fresh access token minted each run by
`scripts/mcp-oauth-refresh.sh`). Its tools surface as `mcp__posthog__*` — **discover
them from the server; the tool descriptions and their parameters are the source of
truth, don't assume a fixed list or fixed argument names.** The tools you'll reach for
are the ones for **scope** (list organizations, list projects, switch the active
organization/project — typically named like `organizations-get`, `projects-get`,
`switch-organization`, `switch-project`) and **error tracking** (list a project's
errors over a date range and fetch one error's detail — typically `list-errors` /
`error-details`). Use whatever the server actually exposes.
- **No `mcp__posthog__*` tool callable** → the server isn't connected (or its OAuth
secrets are missing, in which case the workflow logged a `::warning::` and skipped
MCP for the whole run). Log `POSTHOG_NOT_CONNECTED`, notify **once** pointing the
operator at the dashboard → MCP → **Connect PostHog**, and exit.
- **Tools exist but return 401 / "invalid token" / "insufficient scope"** → the OAuth
access token expired and the refresh failed (typically a rotated refresh token that
couldn't be saved back — durable headless refresh needs `GH_SECRETS_PAT`; see
`docs/mcp-oauth.md`), or the granted scopes are too narrow. Log `POSTHOG_AUTH_STALE`,
notify the operator to **re-connect PostHog once** in the dashboard, and exit with
whatever partial results already came back (clearly marked partial).
**"All my projects" is only as wide as the OAuth grant.** Connect requests read scopes
(`user:read`, `organization:read`, `project:read`, `error_tracking:read`) across the
organizations the operator authorizes — `user:read` is required just to open the MCP
session. If projects are missing from the digest, the grant almost certainly doesn't
include them — say so once rather than silently under-reporting.
## Steps
### 1. Enumerate the scope
List the organizations the key can access, then the projects in each (switch the
active organization first if the server requires it before listing its projects).
Build the working set of `{org, project id, project name, region host}`. Apply any
`${var}` name filter here. Region host: prefer whatever the tool returns; otherwise
`us.posthog.com` for US, `eu.posthog.com` for EU — you need it to build links later.
**Call budget: ≤ 60 MCP tool calls per run.** These calls are read-only and unmetered
(no per-call spend), so the cap is a runtime guard, not a money limit — but respect
it. Enumeration is cheap (a handful of calls); the bulk is one `list-errors` per
project below. If the operator has more projects than the budget allows after
enumeration, cover projects **in listed order**, and in the digest name exactly which
projects were **not** reached this run (a silent cap reads as "all clear" when it
isn't — see seo-audit's `--max` discipline).
### 2. Pull each project's errors
For each project in scope: switch the active project to it, then list its errors for
the window — `dateFrom` = 7 days before ${today} (or the `${var}` window), `dateTo` =
${today}. Order by **occurrences** and request the top ~15 issues; filter out test
accounts if the tool offers it. Capture per issue, **verbatim from the tool result —
never invent or round a number**: the error name/message, occurrence count, users
affected, first-seen and last-seen timestamps, and any status (resolved/suppressed)
and per-day/sparkline counts the tool returns.
A project that errors or returns nothing: record it (0 errors, or the error) and
**keep going** — one unreachable project must not abort the rest. Only fetch
`error-details` for the **top ~5 issues across all projects** (for a one-line "what /
where" in the digest), and only if the list view didn't already carry it — that keeps
you well inside budget.
### 3. Rank and classify
Across all projects, build one impact-rankeSet up and run an Aeon agent instance — get started from scratch, pick which skills to turn on or install more from packs, reschedule or change what runs, edit what an existing skill does, fix a skill that isn't firing, set the STRATEGY.md north star and soul/ voice, turn a coding-agent chat into a scheduled Aeon skill, and mine past coding-agent conversations for recurring work worth automating as a skill. Use when the user mentions Aeon, aeon.yml, an Aeon skill / instance / routine / pack, asks to schedule, enable, edit, or debug an agent that runs on a cron, or asks what of their repeated/manual work Aeon could take over.
Mention/keyword sweep on social platforms for [REPLACE: KEYWORDS] — trends, sentiment, top posts
5 concrete real-life actions, leverage-scored against open loops with specificity and anti-fluff gates
Static config-correctness linter for this instance - catches the silent-failure class (unquoted schedules, duplicate keys, unconfigured skills, mode typos, broken requires/MCP refs) that no run-based health skill can see. Notifies only on problems.
Pull framework updates from the upstream Aeon repo into this instance - 3-way merges canon's new commits into a PR, never clobbering operator config.
Write a publication-ready article in one of three angles - a trending long-form piece, a watched-repo thesis, or a project-through-a-lens essay. Optional Replicate hero image with --visual.
Automatically merge open PRs that have passing CI, no blocking reviews, and no conflicts
Two-mode aeon.yml workflow builder - analyze inspects URLs and emits a tiered, signal-verified skill-enablement plan plus an aeon.yml diff; enable flips slugs to enabled:true and opens a PR.