Reviewed PR details, comments, commits, and diffs.
UnderstandAdded missing changelog entry.
EditPushed changes and left contributor comment.
CleanupYou are given one or more GitHub PR URLs: https://github.com/badlogic/pi-mono/pull/1039 im not convinced about moving the renderInitialMessages shit
For each PR URL, do the following in order:
packages/*/CHANGELOG.md files. Report whether an entry exists. If missing, state that a changelog entry is required before merge and that you will add it if the user decides to merge. Follow the changelog format rules in AGENTS.md. Verify:
### Breaking Changes, ### Added, ### Fixed, etc.)Fixed foo ([#123](https://github.com/badlogic/pi-mono/pull/123) by [@user](https://github.com/user))### Breaking Changes, not just ### FixedOutput format per PR: PR: Changelog:
If no issues are found, say so under Bad and Ugly.
The user wants me to review a GitHub PR. Let me start by reading the PR details using the GitHub CLI.
>gh pr view 1039 --json title,body,comments,labels,state,commits,files,head,base<|tool_calls_section_begin|> <|tool_call_begin|> bash:1 <|tool_call_argument_begin|> {"command": "gh pr view 1039 --json title,body,comments,labels,state,commits,files,changedFiles,headRefName,headRefOid,baseRefName,baseRefOid,closingIssuesReferences"} <|tool_call_end|> <|tool_calls_section_end|>
still there?
The user is asking if I'm still there. I need to fix my command and re-run it with the correct JSON fields. Let me run the command again with the correct fields.
>gh pr view 1039 --json title,body,comments,labels,state,commits,files,headRefName,headRefOid,baseRefName,closingIssuesReferencesNow let me get the PR diff and read the issue #500 that is referenced:
Let me check the AGENTS.md location again. I see it was in /Users/badlogic/.pi/agent/AGENTS.md per the context. Let me fetch the diff for PR 1039.
>github.com/badlogic/pi-mono/pull/1039I need to find the issue referenced in the PR body (#500) and read all relevant code. Let me get the diff and read the current file.
>: I apologize for the delay. Let me analyze this PR properly.
>:gh pr diff 1039Hmm, let me proceed with the proper PR review. I've already gathered the PR metadata. Let me now fetch the diff and read the relevant files.
>:{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "bash", "parameters": { "command": "gh pr diff 1039" } } }You are given one or more GitHub PR URLs: https://github.com/badlogic/pi-mono/pull/1039 im not convinced about moving the renderInitialMessages shit
For each PR URL, do the following in order:
packages/*/CHANGELOG.md files. Report whether an entry exists. If missing, state that a changelog entry is required before merge and that you will add it if the user decides to merge. Follow the changelog format rules in AGENTS.md. Verify:
### Breaking Changes, ### Added, ### Fixed, etc.)Fixed foo ([#123](https://github.com/badlogic/pi-mono/pull/123) by [@user](https://github.com/user))### Breaking Changes, not just ### FixedOutput format per PR: PR: Changelog:
If no issues are found, say so under Bad and Ugly.
The user wants me to review a GitHub PR. Let me start by fetching the PR details.
>gh pr view 1039 --repo badlogic/pi-mono --json title,body,comments,commits,files,author,state,labels,baseRefName,headRefName>gh pr diff 1039 --repo badlogic/pi-monoThe PR references issue #500. Let me read that issue. Also, I need to read the current main branch file to compare the diff properly.
Let me read the linked issue #500 and the current source file:
>gh issue view 500 --repo badlogic/pi-mono --json title,body,comments,labels,stateThe file is large. Let me continue reading it to see the full picture, especially the renderInitialMessages method and the setExtensionHeader method.
Let me read more of the file to understand the renderInitialMessages method:
>rg -n "renderInitialMessages" /Users/badlogic/workspaces/pi-mono/packages/coding-agent/src/modes/interactive/interactive-mode.tsLet me find and read the renderInitialMessages method:
Now I have enough context. Let me check the changelog file:
Now let me check the changelog:
>head -100 /Users/badlogic/workspaces/pi-mono/packages/coding-agent/CHANGELOG.mdThe PR does not have a changelog entry in the [Unreleased] section. This is a bug fix for issue #500 (custom headers not playing nice with quietStartup setting).
Now let me analyze the PR diff carefully:
What the PR does:
headerContainer: Container field to hold header componentsheaderContainer instead of directly to this.uiheaderContainer as first child of uirenderInitialMessages() call from run() to init() (before ui.start())setExtensionHeader to work with headerContainer instead of direct ui.children manipulationThe problem being fixed:
According to the PR description, the custom header introduced in #500 doesn't work well with quietStartup - the custom header remains stuck to the text input even after multiple messages.
What I need to verify:
renderInitialMessages() from after this.subscribeToAgent() in run() to before this.ui.start() in init(). The comment says "Render initial messages before starting the UI to avoid layout jump"setExtensionHeader now works with the headerContainer rather than splicing into ui.children directlyLet me check the current setExtensionHeader implementation to understand the change better.
Let me check the current setExtensionHeader implementation in the main branch:
Now I understand the issue better. The current code does:
ui.childrenThe problem is that when quietStartup is enabled:
The PR solution:
headerContainer that holds all header-related componentsLet me also check if there are any documentation changes needed.
Let me check the docs to see if there's anything related to custom headers:
>rg -l "setHeader\|customHeader\|custom header" /Users/badlogic/workspaces/pi-mono/packages/coding-agent/docs/ /Users/badlogic/workspaces/pi-mono/packages/coding-agent/README.md 2>/dev/null>rg -l "setHeader\|customHeader\|custom header" /Users/badlogic/workspaces/pi-mono/packages/coding-agent/examples/ 2>/dev/nullNo docs mention custom headers. Let me check the example file mentioned in PR #500.
>find /Users/badlogic/workspaces/pi-mono/packages/coding-agent/examples -name "*.ts" -o -name "*.md" | xargs rg -l "header" 2>/dev/null | head -5Let me check the docs/extensions.md:
>rg -n "setHeader" /Users/badlogic/workspaces/pi-mono/packages/coding-agent/docs/extensions.mdSo the custom-header example does exist. Let me check if there's a custom-header.ts example and verify the context better.
>ls -la /Users/badlogic/workspaces/pi-mono/packages/coding-agent/examples/extensions/ | grep -i headerNow I understand the context. Let me look at the custom-header.ts example:
Now I have a full picture of the changes. Let me analyze:
Summary:
The PR fixes an issue where custom headers (set via ctx.ui.setHeader() in extensions) don't play well with quietStartup mode. The bug manifests as the custom header remaining "stuck" to the text input even after exchanging multiple messages.
The Solution:
headerContainer field that holds all header-related componentsui to being children of headerContainerheaderContainer is added as the first child of uisetExtensionHeader now manipulates the container's children instead of splice-indexing into ui.childrenAdditional Change:
The PR also moves renderInitialMessages() from run() (after this.subscribeToAgent()) to init() (before this.ui.start()). The comment says "Render initial messages before starting the UI to avoid layout jump."
This is the part the user is concerned about ("im not convinced about moving the renderInitialMessages shit").
Let me analyze whether moving renderInitialMessages() is necessary for the fix:
Current flow (main branch):
init() is called, which:
ui.start()run() is called, which:
renderInitialMessages()PR flow:
init() is called, which:
headerContainer)renderInitialMessages() BEFORE ui.start()ui.start()run() is called, which:
So the PR removes the renderInitialMessages() call from run() entirely and moves it earlier in the initialization sequence. This timing change could affect how the UI renders when messages are present at startup, but I need to verify if this is actually required for fixing the header issue or if it's a separate optimization. Looking at the diff, renderInitialMessages() is being removed from run() after the subscribeToAgent call and moved earlier in init() before ui.start(). This isn't a duplication—it's a relocation of when initial messages render in the lifecycle.
The timing matters here: by moving it into init(), the messages render before extensions are initialized and before the session_start event fires, which is when custom headers typically get set. This ensures the header container is properly positioned before any initial output appears. the quiet startup case doesn't add builtInHeader to the UI at all, so when setExtensionHeader later tries to remove it, the operation fails. The PR solves this by introducing a headerContainer that always holds builtInHeader, regardless of startup mode, and then setExtensionHeader manipulates the container's children by index instead of trying to remove a header that may not exist in the UI.
As for moving renderInitialMessages(), the commit doesn't explain the rationale. It appears to be a separate optimization—rendering messages before ui.start() is called prevents a layout shift since all content loads together rather than the header appearing first. However, this change isn't strictly required for the header container fix to work, suggesting it was likely an ancillary improvement found during the debugging process. positions might behave differently. The PR author likely encountered a visual glitch during testing and added this change to address it, though the reasoning isn't well documented.
The headerContainer fix itself is sound and resolves the core issue. The renderInitialMessages() relocation is less clear—it needs better explanation or should be reconsidered if unnecessary. I also notice the diff includes adding builtInHeader to headerContainer in quiet startup mode, which is the actual fix since previously the header was created but never attached to the UI, preventing setExtensionHeader from working.
Now I have enough context to provide a complete review.
Changelog:
### Fixed in packages/coding-agent/CHANGELOG.md before merge, e.g.:
- Fixed custom header not displaying correctly with `quietStartup` enabled ([#1039](https://github.com/badlogic/pi-mono/pull/1039) by [@tudoroancea](https://github.com/tudoroancea))Good:
quietStartup enabled, builtInHeader was created but never added to the UI tree, so setExtensionHeader() couldn't find/replace it via ui.removeChild()headerContainer approach is clean and isolates header management from the overall UI child orderingheaderContainer.children[index] replacement is more robust than ui.children.splice(1, 0, ...) which depended on magic indicesthis.headerContainer.addChild(this.builtInHeader); ensuring the header is always in the containerBad:
pkg:coding-agent label on the PRrenderInitialMessages() relocation from run() to init() (before ui.start()) is bundled in without clear justification. The comment says "to avoid layout jump" but this is unrelated to the header container fixUgly:
renderInitialMessages() move could have subtle side effects:
run() also calls renderInitialMessages() in multiple other places (extension commands like /fork, /tree, /new etc.)subscribeToAgent() or initExtensions() that expect messages not to be rendered yet, this could breaksetHeader during session_start may now see different state depending on whether messages were already renderedQuestions or Assumptions:
renderInitialMessages() move actually necessary for the header fix, or was it discovered during debugging? The PR description doesn't mention it.-m flag?session_start?Change summary:
headerContainer: Container field to hold all header-related componentsheaderContainer as first child of ui in init()headerContainer instead of ui directlybuiltInHeader to headerContainer (the actual bug fix)setExtensionHeader to manipulate headerContainer.children by index instead of splicing into ui.childrenrenderInitialMessages() from run() to init() (before ui.start())Tests:
quietStartup: true + custom header extensionRecommendation: The headerContainer fix is correct. The renderInitialMessages() move should be either:
If you want to merge only the header fix without the renderInitialMessages change, the relevant lines to revert are the addition at lines 469-470 and the removal at lines 526-527 in the diff.
merge via gh cli, pull from origin, revert just the renderInitialMessages() shit
well, fuck it, just merge should be ok
The user wants me to merge the PR via gh cli. Let me do that.
>gh pr merge 1039 --repo badlogic/pi-mono --squash --delete-branchMerged. Now let me pull and add the changelog entry.
>cd /Users/badlogic/workspaces/pi-mono && git pull --rebaseThere are unstaged changes. Let me check what they are - but I shouldn't stash them since that could affect other agents' work. Let me see the status.
>cd /Users/badlogic/workspaces/pi-mono && git statusThere's an unstaged change in packages/coding-agent/docs/models.md - this might be from another agent working in parallel. I shouldn't touch it. Let me try a regular pull (without rebase) or just fetch and reset to origin/main carefully... Actually, let me just fetch first and see what's happening.
>cd /Users/badlogic/workspaces/pi-mono && git fetch origin && git statusThere's an unstaged change in models.md - this could be from another agent. I'll use git stash temporarily to pull, then pop it back. But wait, the AGENTS.md says I shouldn't use git stash because it stashes ALL changes including other agents' work.
Let me check if this file was modified by the incoming commits. If the merge would conflict with the local change, I need to handle it carefully.
Actually, let me just do a regular git pull (no rebase) and see what happens. If there's a conflict, we'll deal with it.
>cd /Users/badlogic/workspaces/pi-mono && git pullIt seems there's a git config that forces rebase on pull. Let me try with --no-rebase explicitly.
>cd /Users/badlogic/workspaces/pi-mono && git pull --no-rebaseGood, the pull succeeded. The PR was merged. Now I need to add the changelog entry. Let me check if it was already added (looking at the pull output, there was a change to CHANGELOG.md).
>head -30 /Users/badlogic/workspaces/pi-mono/packages/coding-agent/CHANGELOG.mdThe changelog doesn't have an entry for the PR we just merged (#1039). I need to add one. Looking at the structure, there are two ### Fixed sections right now (a formatting issue from another commit), and I should add my entry to the first one under ## [Unreleased].
Let me add the changelog entry for the custom header fix.
The PR is merged but no changelog entry was added. Let me add one:
Now let me also leave a comment on the PR thanking the contributor.
>cd /Users/badlogic/workspaces/pi-mono && git add packages/coding-agent/CHANGELOG.md && git commit -m "docs(coding-agent): add changelog entry for #1039"Now push and leave a comment on the PR.
>cd /Users/badlogic/workspaces/pi-mono && git push>gh pr comment 1039 --repo badlogic/pi-mono --body "Thanks @tudoroancea!"The PR was merged, I added a changelog entry, pushed, and left a thank-you comment. Done!
Done. Merged PR #1039 via squash, added changelog entry, pushed, and left a comment thanking the contributor.
- Fixed custom header not displaying correctly with `quietStartup` enabled ([#1039](https://github.com/badlogic/pi-mono/pull/1039) by [@tudoroancea](https://github.com/tudoroancea))