You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Spec copy-as-code and open-a-PR for code-managed templates #501
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.
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.
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
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.
(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.
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.
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.
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".
With GitHub connected, PostHog Code available and a stored GitHub repository, the popover gains a button that starts a PostHog Code task with the completed prompt on the template's repository. The task opens the PR.
It uses the existing tasks create and run APIs, as the MCP analytics "create a fix task" button does. It is frontend only, with nothing changed in the template.
Danger areas: a third-party repository write owned by PostHog Code, its auth and its billing.
(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.
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):
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.
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.
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.
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.
Activity
Silthus commentedon Oct 17, 2026
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.
Silthus commentedon Oct 17, 2026
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):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:
template_outdatedpath.create_pull_requestgainsdraft=False.qa-swarm.Pending question: three spec cards
source_repositorynames a GitHub repository.Silthus commentedon Oct 17, 2026
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):source.repository,pathandrefsourceon MCP uploadsClosed as no longer applicable:
Decisions locked
From Michael:
In `<path>`, change …and copies a prompt. The prompt adds:<title>, preview text in<meta name="preheader">, the whole file is the HTML;{{ variables.* }}only, listing the ones the file uses;.git. It reads files only and drops credentials.The spec decided:
source, a one-way door once released.Pending question: Card 4, what does stack B become?
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.
Silthus commentedon Oct 17, 2026
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.
How the spec does it.
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 toolworkflows-request-email-template-change(scopetask:write, never project secret API keys).designing-email-templatesskill tells the agent to checkmanaged_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 carriesmanaged_by: code. The403 immutablefix 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.Tickets (children of #461,
wayfinder:implement, native blocking edges):sourceon MCP uploadsClosed: #504, #505 and #506; #505 and #506 point at their replacements.
Merge-risk danger areas.
task:writeon a viewset that admits project secret API keys for upload and send; PostHog Code runs are billable.sourcecontract.Stack B ships through
qa-swarm.Gaps the tickets prove or record:
Pending question
Accept revision 3?
Silthus commentedon Oct 17, 2026
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:
managed_by. For a code-managed template it never updates it through MCP.change_prompt_context, and the next send uploads it.workflows-request-email-template-change.403 immutablefix 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.Tickets updated:
403 immutabletext, with a test on the exact text.The ticket list, blockers and danger areas are otherwise unchanged from the previous park comment.
Pending question
Accept revision 4?
Silthus commentedon Oct 17, 2026
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):
Stack B, PostHog/posthog (on top of A; ships through
qa-swarm):4. #513 Request a change: route, PostHog Code task, MCP tool,
403 immutablefix 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,pathandrefon upload (PostHog/posthog-js, follow-up PR on PostHog#5312). No blockers.8. #511 The skill passes
sourceon 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:
{{ variables.* }}the file uses, and how the change goes live..git. The skill passes them on MCP uploads. Without a repository, the prompt and the copy still work, with no dialog.POST messaging_templates/{id}/request_change/, the MCP toolworkflows-request-email-template-change, which starts a PostHog Code task) is only for agents and people without access. The tool texts and the403 immutablefix give that order.Decided by the spec:
change_prompt_contextandchange_prompt_starter.Merge-risk danger areas:
task:writeon a viewset that admits project secret API keys for upload and send, and billable runs.sourcecontract.