Skip to content

feat(metrics): add wizard metrics program (runs the context-mill metrics skill) - #1102

Merged
gewenyu99 merged 9 commits into
mainfrom
posthog/metrics-program
Aug 21, 2026
Merged

feat(metrics): add wizard metrics program (runs the context-mill metrics skill)#1102
gewenyu99 merged 9 commits into
mainfrom
posthog/metrics-program

Conversation

@DanielVisca

@DanielVisca DanielVisca commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Problem

PostHog now has an application-metrics product (posthog.metrics — counters, gauges, histograms, alpha), and context-mill is growing a metrics skill family (PostHog/context-mill#342) that teaches the agent where to place metrics calls. The wizard had no command to run it — users would have to know the exact variant id and type wizard skill metrics-python themselves.

Changes

Adds a flat wizard metrics TUI program, the same shape as ai-observability:

  • src/lib/programs/metrics/index.tsProgramConfig with no fixed skillId; the customPrompt has the agent call load_skill_menu with the metrics category and pick the platform variant (python / nodejs / javascript / kubernetes / other-OTLP) from the project manifest, asking via wizard_ask when ambiguous. Additive-only: reuse an existing PostHog client rather than constructing a second one.
  • MetricsIntroScreen — variant-picking programs have no pre-seeded skillId, so the generic intro renders "Let's run the unknown skill"; this mirrors AiObservabilityIntroScreen.
  • Registry entry, bin.ts wiring, switchboard DEFAULT_BINDING, program tests.
  • e2e drivability — registers ScreenId.MetricsIntro in the harness action registry and decideE2eAction, declares the program's path in test/e2e.json, and adds a metrics flow snapshot. Without this a headless run stalls on the intro (see Test plan).

Test plan

pnpm build && pnpm test && pnpm lint1858/1858 tests pass, 0 lint errors.

Recorded walkthrough

A real terminal recording, not a re-render: asciinema in a 116×30 PTY, the wizard driven with actual keystrokes.

What it shows, in order:

  1. The command existswizard --help lists metrics Add PostHog application metrics to your project.
  2. The TUI, keystroke-drivenwizard metrics on a Flask app: the new intro screen, ↓ + Enter into More info (which describes the program and the platform variants), Enter back, Continue, health check, then the auth screen. Interactively the wizard wants a browser OAuth round-trip or a phx_ personal key.
  3. The agent's first action, for realfetchSkillMenu resolves the metrics category (all five variants) and installSkillById('metrics-python') extracts SKILL.md + references, with triage: undefined (the strict path where a warlock-flagged skill fails closed). Production wizard code, no model needed.
  4. The metrics working — the instrumentation applied from that skill, its rules under unit test (5/5), the app booting, deterministic traffic, then a live HogQL query against posthog.metrics:
metric                   type       unit        sum    last  samples
--------------------------------------------------------------------
db.posts.total           gauge      -           7.0       7        1
http.request.duration    histogram  ms       906.73 20.5415       64
http.requests            sum        -          64.0       3        9
posts.created            sum        -           7.0       7        1
users.registered         sum        -           2.0       2        1

  ✔ http.requests          64 (generator 62 + up to 4 probe)
  ✔ posts.created          7 == 7
  ✔ users.registered       2 == 2
  ✔ db.posts.total         last=7 == 7 (gauge)
  ✔ http.request.duration  histogram, 64 samples

PASS — every counter, the gauge and the histogram match the traffic that was just generated.

The pass/fail verdict in the recording is computed from the returned rows (counters on summed delta, the gauge on its last value, the histogram on sample count) and exits non-zero on mismatch — it is not a hardcoded success line.

What the recording does not show

The agent's own model call. This sandbox holds a pha_ OAuth application token, and gateway.us.posthog.com/wizard rejects that app for the wizard product:

$ curl -X POST https://gateway.us.posthog.com/wizard/v1/messages -H "Authorization: Bearer $TOKEN" ...
403 {"detail":"OAuth application not authorized for product 'wizard'"}

The wizard requires llm_gateway:read on a phx_ key (or browser OAuth), and it deliberately strips a direct ANTHROPIC_API_KEY from the agent subprocess (agent-env-isolation.ts) so runs bill through the gateway — so there is no legitimate local bypass, and none was used. Everything up to and including the agent initializing and running this program's flow is real; writing the instrumentation is the one step that needs a wizard-authorised key. Under the repo's ci-mode harness (which injects credentials) the run reaches Agent initialized. Let's get cooking! / Setting up application metrics... before the same 403, and renders a structured error outro rather than a stack trace.

The drivability bug this surfaced

Adding a new intro screen needs it registered in two harness allow-lists. Before the fix, the offline flow trace repeated metrics-intro for all 40 guard iterations — a headless run would hang on the intro forever. The harness's own exhaustiveness test confirms the delta:

uncovered screens
before ['metrics-intro', 'task-notice']
after ['task-notice']

task-notice is a pre-existing gap on main, unrelated to metrics — left alone rather than silently changed. Note these harness tests are currently excluded from pnpm test by vitest.config.ts ("the e2e harness and its tests live in a separate stacked PR"), so they were run explicitly; that exclusion is why the stall wouldn't have failed CI.

The committed metrics flow snapshot now pins the full path:

metrics-intro  → confirm_setup
health-check   → dismiss_outage
auth           → (external)
run            → (external)
outro          → dismiss_outro
keep-skills    → keep_skills

Skill content

Validated end-to-end separately: instrumenting a Flask app from the metrics-python skill produced counter, gauge, and histogram values in PostHog that matched deterministic generated traffic exactly — see PostHog/context-mill#342.

Note: a full agent run needs the metrics category live in skill-menu.json, i.e. context-mill#342 merged + released (or --local-mcp against a local build, as used here). Merge order: context-mill first.


Created with PostHog Desktop

Flat skill command mirroring ai-observability: no fixed skillId — the agent loads the context-mill `metrics` category (PostHog/context-mill#342) and picks the platform variant (python, nodejs, javascript, kubernetes, other/OTLP) from the project manifest. Ships a metrics-specific intro screen, registry + switchboard binding, and program tests.

Generated-By: PostHog Desktop
Task-Id: 495fbacb-61e8-4fdb-8c0f-7f69cd7a3fd6
@github-actions

Copy link
Copy Markdown

🧙 Wizard CI

Run the Wizard CI and test your changes against wizard-workbench example apps by replying with a GitHub comment using one of the following commands:

Test all apps:

  • /wizard-ci all

Test all apps in a directory:

  • /wizard-ci ai-observability
  • /wizard-ci basic-integration
  • /wizard-ci mcp-analytics
  • /wizard-ci revenue
  • /wizard-ci self-driving

Test an individual app:

  • /wizard-ci ai-observability/anthropic
  • /wizard-ci ai-observability/groq
  • /wizard-ci ai-observability/manual-capture
Show more apps
  • /wizard-ci ai-observability/openai
  • /wizard-ci ai-observability/openai-agents
  • /wizard-ci ai-observability/vercel-ai
  • /wizard-ci basic-integration/android
  • /wizard-ci basic-integration/angular
  • /wizard-ci basic-integration/astro
  • /wizard-ci basic-integration/django
  • /wizard-ci basic-integration/fastapi
  • /wizard-ci basic-integration/flask
  • /wizard-ci basic-integration/javascript-node
  • /wizard-ci basic-integration/javascript-web
  • /wizard-ci basic-integration/laravel
  • /wizard-ci basic-integration/next-js
  • /wizard-ci basic-integration/nuxt
  • /wizard-ci basic-integration/python
  • /wizard-ci basic-integration/rails
  • /wizard-ci basic-integration/react-native
  • /wizard-ci basic-integration/react-router
  • /wizard-ci basic-integration/sveltekit
  • /wizard-ci basic-integration/swift
  • /wizard-ci basic-integration/tanstack-router
  • /wizard-ci basic-integration/tanstack-start
  • /wizard-ci basic-integration/vue
  • /wizard-ci mcp-analytics/custom-dispatcher
  • /wizard-ci mcp-analytics/typescript-sdk
  • /wizard-ci revenue/stripe
  • /wizard-ci self-driving/astro
  • /wizard-ci self-driving/fastapi
  • /wizard-ci self-driving/nuxt
  • /wizard-ci self-driving/react-router
  • /wizard-ci self-driving/sveltekit

Results will be posted here when complete.

Adding a new intro screen requires registering it in two harness allow-lists; without them a headless run stalls on the intro forever (the flow trace repeated metrics-intro for all 40 guard iterations). Registers ScreenId.MetricsIntro in the action registry and decideE2eAction, declares the program's e2e path in test/e2e.json, and adds a metrics flow snapshot so the walkthrough is regression-covered.

Pre-existing, unrelated: the action-registry exhaustiveness test still reports `task-notice` as uncovered on main; left alone here.

Generated-By: PostHog Desktop
Task-Id: 495fbacb-61e8-4fdb-8c0f-7f69cd7a3fd6
@DanielVisca
DanielVisca marked this pull request as ready for review August 18, 2026 18:35
@DanielVisca
DanielVisca requested a review from a team as a code owner August 18, 2026 18:35
@gewenyu99

Copy link
Copy Markdown
Collaborator

Hey @DanielVisca Will be looking at this today, sorry for being a little late.

I'll be looking to do a few things on stacked PRs

  • I think I'm gonna move your program to GLM or Sol-medium on the Pi harness. default Sonnet 4.6 on high is likely the wrong model for this task
  • Do you need the PostHog SDKs already installed? We can knock it out in one go instead of having them run two commands

gewenyu99 and others added 5 commits August 21, 2026 13:13
…1129)

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…iant machinery on the wizard side too

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…inear prompt pull the matching one themselves

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…lows them

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
'publish_handoff',
];

const OPT_IN_WIZARD_TOOLS = ['wizard_ask', 'load_skill_menu', 'install_skill'];

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Medium: Skill installation can escape the workspace

Registering install_skill here makes the existing unsafe destination calculation reachable from remote task prompts. The installer passes the registry-controlled skillEntry.id to path.join(installDir, '.claude', 'skills', skillEntry.id) without verifying that the result remains under .claude/skills; an attacker controlling the skill registry can use an ID such as ../../../../target to write the downloaded bundle outside the project, and a rejected scan subsequently calls rmSync on that escaped directory. Validate skill IDs against a strict format and resolve the destination before any directory creation, download extraction, scanning, or cleanup, rejecting paths that are not descendants of the intended skills root.

@veria-ai

veria-ai Bot commented Aug 21, 2026

Copy link
Copy Markdown

PR overview

This pull request adds a wizard metrics program that runs the context-mill metrics skill through the agent task harness.

One security issue remains open in the skill installation flow. A registry-controlled skill identifier can escape the workspace path, allowing an attacker who controls registry content to write or delete files outside the intended skills directory. No issues have yet been addressed.

Open issues (1)

Fixed/addressed: 0 · PR risk: 7/10

@gewenyu99

Copy link
Copy Markdown
Collaborator
Screenshot 2026-08-21 at 5 55 49 PM Works great, added verify/install SDK steps + basic monorepo support

@gewenyu99 gewenyu99 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

This looks good. 1 last change before I merge
-> code owners
-> fixing handoff

@gewenyu99
gewenyu99 enabled auto-merge (squash) August 21, 2026 22:30
@gewenyu99
gewenyu99 merged commit 9f45ef5 into main Aug 21, 2026
17 checks passed
@gewenyu99
gewenyu99 deleted the posthog/metrics-program branch August 21, 2026 22:32
joshtronic pushed a commit to joshtronic/wizard that referenced this pull request Aug 22, 2026
…trics skill) (PostHog#1102)

Co-authored-by: Vincent (Wen Yu) Ge <vincent@posthog.com>
Co-authored-by: Vincent (Wen Yu) Ge <29069505+gewenyu99@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants