Skip to content

Spec copy-as-code and open-a-PR for code-managed templates #501

Closed

Description

@Silthus

Question

What exactly do the two follow-up stacks build, and how do they split into PRs?

  • Stack A, copy as code: edit a code-managed template visually and copy it back to the repository file.
  • Stack B, open a PR: with GitHub connected, the same button opens a PR that updates the file.

Stack A stacks on PostHog#118924, and stack B stacks on stack A. Write the spec from the map's decisions and the research in #500, then slice it into implementation tickets and one ship ticket per stack.

wayfinder:spec

Activity

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

    @Silthus
    OwnerAuthor

    Runtime: T3 Code
    Thread: thread:project:f66f06fc-0bc1-4bfe-b00a-4aab7f54eb13:7f33dd80-c6a7-42ae-96c6-4138688e4ef2
    Title: spec #501: copy-as-code and open-a-PR for code-managed templates
    Cast: Opus 5.5, high. AFK cap 75 minutes.

  3. Silthus commented on Oct 17, 2026

    @Silthus
    OwnerAuthor

    Note

    🤖 Opus 5.5 responding on behalf of Michael

    Parked: spec written, three cards wait

    Spec: #502 Spec: copy-as-code and open-a-PR for code-managed templates

    Tickets (children of #461, wayfinder:implement, native blocking edges):

    # Stack Repo Slice Blocked by
    #503 A PostHog/posthog Copy a code-managed template as its HTML file none
    #504 A PostHog/posthog Edit locally and copy the edits #503
    #505 B PostHog/posthog Draft PR route #504 (stack order only)
    #506 B PostHog/posthog Open a draft PR from the template page #505, #504
    #507 docs PostHog/posthog.com Docs section and error anchors #505

    No ship tickets or branches: the conductor wires one ship ticket per stack.

    Decisions locked

    All of these are binding from the map. The spec also decided:

    • Preview stays the default, with an explicit "Edit locally". Local edits are never persisted: submit, the save loader and any draft autosave all refuse. The server lock is untouched.
    • The file is the SDK's HTML contract. An unedited or HTML-block-only edit copies back as the author's own bytes. A canvas edit becomes generated HTML, with a notice. The file never carries a text part; a stored one warns but never blocks.
    • Copying and opening a PR never publish. The next send from code uploads the file, through the existing template_outdated path.
    • Open a PR sits in the same slot as Copy code. It is session-only, uses the project's GitHub App, and excludes project secret API keys.
    • The base is always the default branch. A PR is refused unless the base file equals the published HTML and the published hash still matches the edit's base.
    • Each request opens one draft PR. Recovery goes through a deterministic branch and the open-PR lookup, with no new table. create_pull_request gains draft=False.
    • No migration, scope, flag or MCP tool.
    • Merge-risk danger areas: a write to a third-party repository, auth and scopes, and the public API. Stack B ships through qa-swarm.

    Pending question: three spec cards

    1. What does local editing promise?
      • (a) The normal editor over the uploaded HTML block: block edits round-trip byte-faithfully, and added editor blocks give generated HTML.
      • (b) A code editor with live preview, and no canvas.
      • (c) Parse the HTML into native editor blocks.
      • Recommend a. Copy as code: edit a code-managed template locally and copy the edits #504's real-editor proof falls back to block-only editing if the generated HTML breaks.
    2. Copy formats?
      • (a) The HTML file only.
      • (b) The HTML file, plus a "Prompt for your agent" that names the source path.
      • Recommend b: agents come first, and PostHog knows the path.
    3. Target when the stored source is incomplete? posthog-node's automatic upload stores only a working-directory-relative path, with no repository.
      • (a) The dialog prefills the repository and path, and the person picks or corrects them. Nothing is stored, and the server checks that the file matches.
      • (b) Offer the PR only when source_repository names a GitHub repository.
      • (c) b, plus SDK detection from CI and hosting environment variables.
      • Recommend a.
  4. Silthus commented on Oct 17, 2026

    @Silthus
    OwnerAuthor

    Note

    🤖 Opus 5.5 responding on behalf of Michael

    Parked again: spec revision 2, one card waits

    Spec: #502, revision 2

    Tickets (children of #461, wayfinder:implement, native blocking edges):

    # Stack Repo Slice Blocked by
    #503 A PostHog/posthog Edit with your agent: copy a prompt for the template's file none
    #509 A PostHog/posthog Copy the template as its HTML file (secondary action) #503
    #510 source PostHog/posthog-js (follow-up PR on PostHog#5312) posthog-node fills source.repository, path and ref none
    #511 source PostHog/context-mill (#433) The skill passes source on MCP uploads #510
    #507 docs PostHog/posthog.com (PostHog#21306) Docs for the agent flow and source detection #503, #510

    Closed as no longer applicable:

    Decisions locked

    From Michael:

    • Card 1: no editing inside PostHog. "Edit with your agent" opens a popover where the person completes In `<path>`, change … and copies a prompt. The prompt adds:
      • the key, repository and ref;
      • the file contract: subject in <title>, preview text in <meta name="preheader">, the whole file is the HTML;
      • {{ variables.* }} only, listing the ones the file uses;
      • how the change goes live, for a file reference and for a send by key.
    • Card 2: the prompt is primary; "Copy HTML file" is secondary.
    • Card 3: the source metadata carries the repository and path.
      • posthog-node detects them in this order: the explicit option; then GitHub Actions, GitLab CI, Vercel and Railway variables; then the nearest .git. It reads files only and drops credentials.
      • The skill passes them on MCP uploads.
      • Without a repository, the prompt and the copy still work, with no dialog.

    The spec decided:

    • The prompt UI is a popover, not a modal.
    • The text part never goes into the file; a stored one warns but never blocks.
    • The SDK change ships as a follow-up PR on Think through the Elements tab PostHog/posthog#5312.
    • No migration, route, scope, flag or MCP change.
    • Merge-risk danger area: the public SDK contract of posthog-node's source, a one-way door once released.

    Pending question: Card 4, what does stack B become?

    • (a) Drop it. The person's own agent edits the file and opens the PR.
    • (b) "Run with PostHog Code".
    • (c) Defer b to the map's "Not yet specified".

    Recommend b. It gives a marketer without a coding agent the way back to code, using the same prompt. Pick c to keep this map independent of PostHog Code's availability and billing.

  5. Silthus commented on Oct 17, 2026

    @Silthus
    OwnerAuthor

    Note

    🤖 Opus 5.5 responding on behalf of Michael

    Parked again: spec revision 3, no open cards

    Spec: #502, revision 3

    Michael, Card 4 → b, widened.

    • "Run with PostHog Code" ships.
    • The core is that PostHog AI in the sidebar and the PostHog bot in Slack recognize a code-managed template and open a PR, instead of updating it through MCP.

    How the spec does it.

    • One action for every surface. POST messaging_templates/{id}/request_change/ {instruction} starts a PostHog Code task on the template's GitHub repository. The task edits the file and opens a PR. The web button, both agents and any MCP client use the same action, through a new MCP tool workflows-request-email-template-change (scope task:write, never project secret API keys).
    • Agents. The designing-email-templates skill tells the agent to check managed_by. For a code-managed template it never updates, patches, designs or uploads. When it already works in that repository, it edits the file itself; otherwise it calls the new tool. The page's sidebar context carries managed_by: code. The 403 immutable fix and the three write tools' descriptions name the new tool. The Slack bot runs the same sandbox agent, skills and tools, so the same change covers it.
    • One prompt builder, on the server. The "About this file" block and the starter are read-only fields on the template. The copied prompt and the task prompt are the same text. This makes stack A start with a small backend slice (Code-managed templates: the change prompt on the template API #512).

    Tickets (children of #461, wayfinder:implement, native blocking edges):

    # Stack Repo Slice Blocked by
    #512 A PostHog/posthog The change prompt on the template API none
    #503 A PostHog/posthog Edit with your agent: copy the prompt #512
    #509 A PostHog/posthog Copy HTML file #503
    #513 B PostHog/posthog Request a change: route, PostHog Code task, MCP tool #512
    #514 B PostHog/posthog Run with PostHog Code in the popover #503, #513
    #515 B PostHog/posthog PostHog AI and the Slack bot route changes to a PR (skill, page context, evals) #513
    #510 source PostHog/posthog-js Fill the source repository, path and ref on upload none
    #511 source PostHog/context-mill The skill passes source on MCP uploads #510
    #507 docs PostHog/posthog.com Docs, error anchors, source detection #503, #510, #513

    Closed: #504, #505 and #506; #505 and #506 point at their replacements.

    Merge-risk danger areas.

    • A write to a third-party repository: PostHog Code, now reachable by agents.
    • Auth and scopes: task:write on a viewset that admits project secret API keys for upload and send; PostHog Code runs are billable.
    • The public API and the SDK source contract.

    Stack B ships through qa-swarm.

    Gaps the tickets prove or record:

    Pending question

    Accept revision 3?

  6. Silthus commented on Oct 17, 2026

    @Silthus
    OwnerAuthor

    Note

    🤖 Opus 5.5 responding on behalf of Michael

    Parked again: spec revision 4, no open cards

    Michael: an agent that can reach the repository, such as the user's own coding agent over MCP, edits the template's file directly. Going through PostHog only makes sense where the client has no access to the repository.

    What changed in #502:

    • Access decides, not the client. Every agent checks managed_by. For a code-managed template it never updates it through MCP.
      • With repository access, it edits the file, following change_prompt_context, and the next send uploads it.
      • Without access (PostHog AI, the Slack bot, a chat client with no checkout), it calls workflows-request-email-template-change.
    • Tool texts. The 403 immutable fix and the update, patch and design tool descriptions give that order: the file first, the request-change tool only as a fallback. The request-change tool calls itself the fallback.
    • The route doesn't detect the caller. It can't know what a caller can reach, so the tool texts and skills steer the choice.

    Tickets updated:

    • #513: tool descriptions and the 403 immutable text, with a test on the exact text.
    • #515: retitled. The skill puts the file first, and there are two eval cases: a coding agent in the repository edits the file without the tool, and a chat agent with no checkout calls the tool.
    • #511: the context-mill skill says to change a code-managed template in its file, never through PostHog.

    The ticket list, blockers and danger areas are otherwise unchanged from the previous park comment.

    Pending question

    Accept revision 4?

  7. Silthus commented on Oct 17, 2026

    @Silthus
    OwnerAuthor

    Note

    🤖 Opus 5.5 responding on behalf of Michael

    Resolution

    Michael accepted Spec: copy-as-code and open-a-PR for code-managed templates (#502), revision 4, on 2026-10-17. Every card is decided.

    Implementation tickets, in stack order

    Stack A, PostHog/posthog (on top of PostHog#118924):

    1. #512 The change prompt on the template API (backend). No blockers.
    2. #503 Edit with your agent: copy the prompt (frontend). Blocked by Code-managed templates: the change prompt on the template API #512.
    3. #509 Copy the template as its HTML file (frontend). Blocked by Edit with your agent: copy a prompt for a code-managed template's file #503.

    Stack B, PostHog/posthog (on top of A; ships through qa-swarm):
    4. #513 Request a change: route, PostHog Code task, MCP tool, 403 immutable fix text. Blocked by #512.
    5. #514 Run with PostHog Code from the popover. Blocked by #503 and #513.
    6. #515 Agents edit the file when they can reach the repository, otherwise request a change (skill, page context, evals). Blocked by #513.

    Source metadata:
    7. #510 posthog-node fills source.repository, path and ref on upload (PostHog/posthog-js, follow-up PR on PostHog#5312). No blockers.
    8. #511 The skill passes source on MCP uploads and changes code-managed templates in their file (PostHog/context-mill#433). Blocked by #510.

    Docs:
    9. #507 Docs section, error anchors, source detection (PostHog/posthog.com#21306). Blocked by #503, #510 and #513.

    Closed as no longer applicable: #504 (visual local edit), #505 and #506 (the PostHog-side PR route and UI, replaced by #513–#515).

    Decisions

    From Michael:

    • Card 1: no editing inside PostHog.
      • "Edit with your agent" opens a popover. The person completes a starter sentence that names the file and copies a prompt.
      • The prompt carries the key, repository and ref, the HTML file contract, the {{ variables.* }} the file uses, and how the change goes live.
      • The read-only preview stays.
    • Card 2 → b: the agent prompt is primary, and "Copy HTML file" is secondary.
    • Card 3: source metadata. posthog-node fills the repository, path and ref. It reads the explicit option first, then GitHub Actions, GitLab CI, Vercel and Railway variables, then the nearest .git. The skill passes them on MCP uploads. Without a repository, the prompt and the copy still work, with no dialog.
    • Card 4 → b, widened. "Run with PostHog Code" ships, and PostHog AI and the Slack bot open a PR instead of updating a code-managed template through MCP.
    • Revision 4: access decides. An agent that can reach the repository edits the file itself. "Request a change" (POST messaging_templates/{id}/request_change/, the MCP tool workflows-request-email-template-change, which starts a PostHog Code task) is only for agents and people without access. The tool texts and the 403 immutable fix give that order.

    Decided by the spec:

    • One prompt builder, on the server, exposed as change_prompt_context and change_prompt_starter.
    • No idempotency key.
    • No extra confirmation before an agent starts a task.
    • The task uses the generic origin.
    • No migration, scope or flag.
    • The text part never goes into the file.

    Merge-risk danger areas:

    • A write to a third-party repository through PostHog Code, reachable by agents.
    • Auth and scopes: task:write on a viewset that admits project secret API keys for upload and send, and billable runs.
    • The public API, and posthog-node's source contract.
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