Skip to content

Run with PostHog Code from the Edit with your agent popover #514

Closed

Description

@Silthus

Map: Map: send code-managed email templates with one PostHog call
Spec: Spec: copy-as-code and open-a-PR for code-managed templates (revision 3), section "Run with PostHog Code in the popover (stack B)"

Cast: Opus 5.5, high
Repository: PostHog/posthog (frontend)
Stack: B, second slice

Question

From the "Edit with your agent" popover, can a person without a coding agent start PostHog Code on their sentence and follow it to a PR?

Delivers end to end.

  • Button. The popover gains "Run with PostHog Code" next to "Copy prompt". It sends the same sentence to Request a change: start a PostHog Code task that opens a PR for a code-managed template #513's route through the generated client.
  • Disabled reasons:
    • "Describe the change first";
    • "PostHog doesn't know this template's GitHub repository" (no source_repository, or not on GitHub);
    • "Connect GitHub to run PostHog Code" (no GitHub integration on the project);
    • absent entirely when PostHog Code isn't available to the project.
  • In flight: the button is disabled and loading, so a double click sends one request.
  • Success: a toast and the notice link the task ("PostHog Code is working on it. It opens a pull request when it's done."). The sentence is cleared. Nothing changes in the template.
  • Errors show detail and fix; the sentence and Copy prompt stay.
  • Events: message template change run requested {template_id} and message template change run failed {template_id, code} (the server event from Request a change: start a PostHog Code task that opens a PR for a code-managed template #513 covers success).

Test seams.

  • Kea logic tests on messageTemplateLogic at the API boundary:
    • the request carries the sentence exactly;
    • one request on a double click;
    • each disabled reason;
    • an error keeps the sentence.
  • A story for the enabled, disabled and success states.
  • Prior art: messageTemplateLogic.test.ts; the MCP analytics "create a fix task" button in products/mcp_analytics/frontend/tool-quality/, for how a page checks the GitHub integration.

Write scope. products/workflows/frontend/TemplateLibrary/: the popover component from #503 and its story, messageTemplateLogic.ts, templateCopy.ts.

Proof.

  • Red: the "one request on a double click" test fails.
  • Green: the logic tests pass.
  • Local: against the private scratch repository Silthus/posthog-workflows-github-scratch:
    1. start a change from the page;
    2. screenshot the popover and the success notice;
    3. follow the task to its PR, and show the PR changes only the template's file.
  • If PostHog Code can't run on the dev stack, record the gap and prove with stories and the mocked API.
  • Screenshots at 1280px with the side panel open and at full width.

Acceptance criteria

  • The button only appears when PostHog Code is available, and says why it's disabled otherwise.
  • One click starts at most one task.
  • Screenshots in the PR.

Blockers

Blocked by #503 (the popover) and #513 (the route).

How to build (map #461)

  • /tdd red-green-refactor, outside-in, at the seams named above. Real Postgres, Valkey and ClickHouse; mock only what the seam section allows.
  • Repo skills apply where the diff touches their area: /writing-tests, /writing-ui-components, /writing-kea-logics, /writing-user-facing-copy, /writing-code-comments, /improving-drf-endpoints, /routing-outbound-api-calls.
  • Read code from origin/spec/code-managed-templates (the fork's integration branch for feat(messaging): upload, send and lock code-managed email templates PostHog/posthog#118924), not from master.
  • Public repo: no usage numbers, customer names, internal metrics, Slack content or security reasoning in code, commits or the PR. Fixture addresses use example.com. The private note the map points at is background only; never quote it.
  • Shipped means a draft PR handed off for review (see the map's Notes for remotes and branches). Never mark ready, enqueue or merge. The conductor names the stack's integration branch.

Activity

  1. self-assigned this
    on Oct 17, 2026
  2. Silthus commented on Oct 17, 2026

    @Silthus
    OwnerAuthor

    Runtime: T3 child task
    Task: node:delegated-task:command%3Amcp%3A1778d880-5a25-404c-80d0-25fc5ccca3b2%3Adelegate-task%3Awf-email-impl-514-1
    Cast: Opus 5.5, high. Cap 180 minutes.

  3. Silthus commented on Oct 17, 2026

    @Silthus
    OwnerAuthor

    Note

    🤖 Opus 5.5 responding on behalf of Michael

    Resolution

    Landed: 60fb98f06a5 on spec/template-request-change (fast-forward 804a0b87d6c..60fb98f06a5).
    Branch: spec/template-request-change/514. No PR: the ship ticket #517 opens it.
    The range also carries the merge of stack A (495bca44dec, which brings #503's popover from 62c695af6cb). #509 was not on stack A yet, so whoever lands second merges it.

    What landed

    • Button. "Run with PostHog Code" sits next to "Copy prompt" in the popover. It sends the sentence exactly as typed to POST messaging_templates/{id}/request_change/ through the generated messagingTemplatesRequestChangeCreate.
    • Shown only when PostHog Code is available. The logic reads GET desktop/access/ once, after a code-managed template loads. It is the same get_desktop_access_decision the route checks. A refusal or a failed check hides the button.
    • Disabled reasons, in this order:
      1. "PostHog doesn't know this template's GitHub repository" (no source_repository, or one that doesn't match the route's github.com/<owner>/<name> pattern);
      2. "Checking the GitHub connection" while the integrations load;
      3. "Connect GitHub to run PostHog Code" (no GitHub integration on the project);
      4. "Describe the change first".
    • In flight: the button is loading, and the logic ignores another click until the request settles.
    • Success:
      • a toast, "PostHog Code is working on it. It opens a pull request when it's done.", with an "Open task" button;
      • the same line and an "Open task" link in the code-managed notice;
      • the sentence goes back to the starter, and the popover closes.
    • Errors: the popover shows the server's detail and fix in an error banner. The sentence and Copy prompt stay. Without an error envelope: "PostHog Code couldn't start." and "Try again in a few minutes."
    • Events: message template change run requested {template_id} when the request leaves, and message template change run failed {template_id, code}.
    • Notice: moved from MessageTemplate.tsx into CodeManagedNotice.tsx, so a story can show it with the task link. Same copy and Duplicate action.

    Proof

    Test seam: messageTemplateLogic with the API mocked at HTTP (useMocks), in messageTemplateLogic.test.ts, block "run with PostHog Code". Stories are the second seam.

    Red, test by test, before each slice:

    Mutation on the final code: dropping isRequestingChangeRun from the guard fails the double-click test with Received length: 2 (log).

    Green:

    • messageTemplateLogic.test.ts: 49 passed (log).
    • Every suite under TemplateLibrary/ plus lib/components/Git: 7 suites, 100 passed, nothing skipped (log).
    Case Asserts
    sentence with a trailing space the request body is {instruction} with the sentence byte for byte; requested event
    two clicks in one tick one request
    access allowed: true / false / 503 postHogCodeAvailable true / false / false
    starter only / no repository / GitLab / no GitHub integration the exact disabled reason, and no request after a click
    201 task kept for the notice, sentence back to the starter, popover closed, toast with "Open task"
    400 github_repository_not_connected / 500 without a body detail and fix (or the fallback) kept; sentence, popover and Copy prompt kept; failed event with code / null

    Local gate on the landed tree:

    • tsgo --noEmit --checkers 1 in frontend/ through fleet heavy: exit 0 (log).
    • pnpm --filter=@posthog/frontend fix: exit 0.
    • pnpm install --frozen-lockfile: consistent.
    • The pre-push hook (hogli ci:preflight --strict): "failures": 0 (log).
    • No backend change, so no build:openapi or mypy run.

    Screenshots, Storybook from this worktree, API mocked at HTTP, MockHog project, example.com-style repository, no customer data. Narrow is a 560px window, about the scene of a 1280px window with the side panel open. Wide is 1440px.

    Template page (real App scene, scratch story, not committed):

    Narrow (560px) Wide (1440px)
    Change described, button enabled described described
    Refused: detail and fix refused refused
    Started: toast and notice link started started

    Committed stories, Products/Workflows/Template library/Edit with your agent. The 640px story frame clips at 560px, so read the page shots above for narrow:

    Story Narrow Wide
    RunWithPostHogCode (enabled) 560 1440
    RunWithPostHogCodeNeedsGitHub (disabled, tooltip on hover) 560 1440
    RunWithPostHogCodeStarted (notice with the task link) 560 1440
    error banner (scratch story) 560 1440
    WithAPath, unchanged: no access mock, so no button 560 1440

    A browser script counted request_change POSTs per story: 0 for the enabled and disabled stories, 1 for the started and refused ones.

    Gaps

    Calls made

    • Availability comes from desktop/access/. It runs the route's Desktop access decision. Credits are not checked on the page: an organization without credits sees posthog_code_not_available with its fix in the popover.
    • The GitHub check is "any GitHub integration on the project", as the MCP analytics button does. Whether the integration reaches this repository stays the server's github_repository_not_connected error.
    • Disabled-reason order: the reasons that typing can't fix come first. Otherwise a person describes the change and only then learns it can't run.
    • "Checking the GitHub connection" is one extra string. Without it, a page that is still loading integrations would say "Connect GitHub".
    • Error copy comes from the server. Request a change: start a PostHog Code task that opens a PR for a code-managed template #513 gives every code its own detail and fix, so the page shows both and keeps no second table of messages. The only frontend copy is the fallback for a response without the envelope.
    • Errors show inline in the popover, not in a toast. They stay next to the sentence, which stays for a retry. A new run clears the banner.
    • The request is a listener, not a kea loader. A loader failure gets the global error toast from initKea, which would duplicate the banner. Turning that off means editing frontend/src/initKea.ts, outside this product.
    • The task link is urls.taskDetail(task_id), an in-app route, not the absolute task_url.
    • The requested event fires when the request leaves, after the guards. A blocked click sends no event.
    • Cmd+Enter still copies. It does not start a billable run.
    • templateCopy.ts is unchanged. Nothing in it relates to this slice.
    • Route gates unchanged, as the brief said. The open question on Request a change: start a PostHog Code task that opens a PR for a code-managed template #513 about calls from inside a sandbox doesn't affect this button.
    • This worktree needed pnpm install after the stack A merge, because Edit with your agent: copy a prompt for a code-managed template's file #503 added @testing-library/dom and user-event to products/workflows.
    • No review ran in this ticket. Ship stack B: request a change through PostHog Code #517 owns the qa-swarm review.

    Follow-ups

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions