Skip to content

Name native Claude and Codex chats after their first message - #25724

Merged
brennanb2025 merged 34 commits into
mainfrom
brennanb2025/native-chat-naming-agent
Oct 6, 2026
Merged

brennanb2025 merged 34 commits into
mainfrom
brennanb2025/native-chat-naming-agent

Conversation

@brennanb2025

@brennanb2025 brennanb2025 commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor
Files Added Deleted Net
Test 37 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​4342 $\color{#cf222e}{\Huge{\mathbf{−}}}$​14 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​4328
Prod 85 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​2568 $\color{#cf222e}{\Huge{\mathbf{−}}}$​435 $\color{#1a7f37}{\Huge{\mathbf{+}}}$​2133

ELI5

Structured native chats — the new Claude and Codex chat UI (contentType: 'agent-session' tabs) — are never named. Every tab stays “Claude Chat” or “Codex Chat” because the host publishes a fixed title, while the existing AI Vault naming path only handles terminal tabs. The sidebar also loses manual structured-chat names and treats a name such as auth/login as a directory.

After the first message, a separate agent call generates a short name for the tab, sidebar row, and AI Vault. Until that call succeeds, the chat keeps “Claude Chat” or “Codex Chat”. With naming off, new chats keep that ordinary label; a failed call also leaves the chat unnamed. A manual tab rename wins everywhere; clearing it reveals the saved generated name.

What Changed

Both Claude and Codex use the same live-turn observer, covering accepted and admitted sends. Naming runs through the configured-agent machinery already used for commit messages and branch names; sending a message never waits for it. Replay and active orchestration workers do not start naming.

Only an agent-generated name is written into the existing conversation-name field. The write succeeds only while that field is still empty, preserving a name changed during generation. Host tab snapshots advance their version when the saved name changes, and the sidebar and Vault read the same field. The user's separate manual label retains priority; immutable tab indexes avoid repeated row scans. Vault results retain the saved name when the tab closes, including when generation finishes after closure. A live saved-title update uses the existing versioned tab stream; census, reconnect and initial cache loading recover missed names through bounded, exact record lookups on the existing title resolver. Ordinary status updates do not trigger those lookups.

Eligibility comes from the existing host journal. It must contain exactly one non-command root user message and its matching submission made after this host run began. That message has been accepted by Orca, and it can still be waiting for the provider to admit it; a submission already marked rejected is excluded. A first turn finishing while the journal is read does not disqualify that live first-message attempt. The handler remembers its single attempt for the remainder of the run. Later messages expire eligibility; after a restart, the older submission is ineligible even if it was the only message. Disabled, failed, declined, empty, or unreadable-journal attempts are never automatically retried. No new durable attempt flag or record field is added. A command-only turn such as /compact leaves the opportunity available for the first ordinary message. An actual empty first prompt spends that opportunity and writes nothing.

On the owning desktop host, Settings → Chat has separate Appearance and Chat names sections, each with its own heading and card. Chat names previously shared the Appearance card, which made naming look like an appearance preference. The page now uses the existing stacked section structure and card primitives; the naming controls keep their own chat-names anchor and are searchable by “chat names”, “name”, or “Name chats automatically”. Chat names uses the same agent picker, CLI arguments and editable command template as the existing agent action rows. The enable toggle applies independently of Git's AI settings. Selecting Custom command also exposes the existing executable field in Chat, so that choice is configurable with Git's AI settings off. Saving or discarding a template uses the existing settings write queue and unsaved-changes guard. All six languages have the new labels. The action stays out of Git action lists and repository overrides. The owner’s Chat page has merged into main, so this PR includes the controls and naming behavior together. One main-based PR keeps the complete feature reviewable without a second PR depending on unmerged backend work.

Why

Reusing the existing text generator preserves agent selection, account environment, model discovery, timeout, cancellation, and local/remote execution behavior. The existing record field avoids a second name store or a status-name field. The native execution host owns this operation; SSH workspaces never silently launch naming on the client.

Differences from the common pattern:

  • Intended: a chat keeps its ordinary provider label until generation succeeds. Disabled or failed naming leaves no saved name, matching the owner's display decision.
  • Intended: eligibility expires rather than recording an obligation to retry. The first submission must belong to this host run, and only one attempt is permitted. Restarting before naming starts can leave that chat unnamed; this safely avoids repeated agent calls and cannot block a turn.
  • Intended: an unreadable journal leaves the chat unnamed because its first-turn eligibility cannot be proved. The latest status text cannot safely establish that history.
  • Intended: chat recipes stay in the existing per-action settings storage while their editor is in Chat settings. Git enablement and repository recipes do not control chat names.
  • Intended: Custom command uses the existing executable shared by text recipes. Chat exposes that same field only for the custom choice or an edited draft, and its explanation identifies the shared use. Save/Discard applies to executable edits together with the naming recipe; no second command configuration is stored.
  • Intended: the user's manual name remains the existing tab label and outranks the record name. An in-flight call can finish after a manual rename; its saved result stays hidden until that manual label is cleared. This preserves the user's visible choice and gives clearing the label a useful saved name to reveal.
  • Intended: generation inherits the existing 60-second process timeout and account-home queue. Queueing cannot block a user turn; the ordinary chat label remains available.
  • Intended: the provider-neutral live-turn observer starts naming outside the send path. /clear creates an unnamed replacement that is eligible on its first message.
  • Intended: Vault keeps names in its existing display cache and recovers missed updates through finite batches of record lookups at census, reconnect and cache initialization. The record remains the only durable name source; exact host and conversation ownership checks reject stale replies, and ordinary status updates do no naming lookups.
  • Temporary: paired web clients cannot configure the host’s automatic naming preferences through the current settings API. Naming controls and their search result are hidden there; Chat appearance controls and saved-name display remain available. A follow-up must add an explicit host-owned naming-settings capability before exposing remote configuration.
  • Temporary: journal user-role messages do not distinguish internal agent mail from a person's text. Active workers are excluded, but an unnamed chat receiving mail first may use it as context. A follow-up must join durable message provenance; excluding every host-origin send would also exclude legitimate queued and launch prompts.

Writing names back into the provider's history remains a separate follow-up.

Linked Issue

Owner-dispatched native chat naming work; no separate issue.

Visual Proof

The settings layout follow-up on 2080a01c77e9 separates Appearance and Chat names into peer heading/card sections. The required Codex gpt-5.6-terra medium driver and implementing worker personally inspected the three full hidden-renderer Electron frames below, on the exact worktree with an isolated profile. Real settings search found “chat names”, “name”, and “Name chats automatically”; an unsaved template stayed visible with Save/Discard after an unmatched search. The isolated app was safely closed after inspection. These new Settings frames replace the previous settings layout screenshots; the earlier naming-behavior images below remain attributed to their capture commits.

Separate Appearance and Chat names sections, naming enabled

Before: shared card, naming disabled (14bafed595a6) After: separate sections, naming disabled (2080a01c77e9) Unsaved template survives unmatched search
Previous shared Appearance and Chat names card Separate sections with naming disabled Unsaved naming template survives search

Six fresh full hidden-renderer Electron frames confirm both providers on current commit 08959b00bc7b, after integrating main 7faa9f7cd3bd. Each is the same fresh chat before generation, after one separate naming call, and after closing its tab. The implementing worker and prescribed driver personally inspected every full frame and checked the corresponding saved record and invocation count. These captures run real Orca adapters, hooks, storage and UI with isolated provider protocol fixtures; they do not assess live-provider naming quality.

Claude: ordinary provider label while naming; then QA Main quartz on tab, sidebar and Vault; the same Vault row retains it after real tab closure without a refresh. The record has no generated name before the call and the saved name afterward; the manual label is null and only one naming call runs.

Naming pending Name on all three surfaces Name retained after closing
Claude naming pending Claude generated name Claude name retained in Vault

Codex: ordinary provider label while naming; then QA Main willow on tab, sidebar and Vault; the same Vault row retains it after real tab closure without a refresh. The record has no generated name before the call and the saved name afterward; the manual label is null and only one naming call runs.

Naming pending Name on all three surfaces Name retained after closing
Codex naming pending Codex generated name Codex name retained in Vault

Twelve full hidden-renderer Electron frames were captured on 767232389142 and independently inspected by the prescribed driver and implementing worker. Each fresh chat made exactly one separate naming call. The saved-name and Vault implementation remains unchanged; the subsequent main merge adds provider reasoning support while retaining the naming observer. Fresh current-main provider confirmation is shown above.

The real adapters, first-message observer, configured-agent process, saved record and rendered surfaces run against isolated provider protocol fixtures. These captures prove Orca’s behavior; live-provider naming quality is not claimed. All test windows remain hidden.

Claude: QA Vault haze. The tab, sidebar and matching Vault row show the generated name; closing the tab retains that same name in Vault. No Vault refresh is used between the mounted-row capture and closing.

Naming pending Name on all three surfaces Name retained after closure
Claude naming pending Claude name on all three surfaces Claude name retained after closure

Codex: QA Vault maple. The tab, sidebar and matching Vault row show the generated name; closing the tab retains that same name in Vault. No Vault refresh is used between the mounted-row capture and closing.

Naming pending Name on all three surfaces Name retained after closure
Codex naming pending Codex name on all three surfaces Codex name retained after closure

Claude: QA Vault linen. The tab closes while generation is pending; the mounted Vault row automatically changes from the ordinary provider label to the saved name after generation completes. No Vault refresh is used between the mounted-row capture and closing.

Naming pending Tab closed while naming Name arrives after closure
Claude naming pending Claude tab closed while naming Claude name arrives after closure

Codex: QA Vault cedar. The tab closes while generation is pending; the mounted Vault row automatically changes from the ordinary provider label to the saved name after generation completes. No Vault refresh is used between the mounted-row capture and closing.

Naming pending Tab closed while naming Name arrives after closure
Codex naming pending Codex tab closed while naming Codex name arrives after closure

Earlier naming and manual-label behavior was captured on 14bafed595a6 through the actual Settings → Chat controls and Change Title editor. Both the prescribed driver and implementing worker inspected those frames. The saved-name and manual-label implementations are unchanged by the layout follow-up. These are isolated provider fixtures, with real Orca adapters, persistence and UI; the newer Settings layout proof appears above.

Turning off Chat names in Settings prevents a naming call: a new Codex chat completes two turns, has no saved name, and keeps “Codex Chat” on all three surfaces.

Two normal turns with zero naming calls

Selecting Codex as the naming agent and saving the recipe is used by the next fresh Claude chat. One separate Codex invocation saves “Fixture Codex Chat Title”, visible on its tab, sidebar and matching Vault row.

A Claude chat named by Codex

Editing the Custom command executable, CLI arguments and template through the controls is used by the next fresh Codex chat. The child receives exactly --variant=alt --delay-ms=6000 and reads Settings fern from standard input using {firstPrompt}. It saves “ALT Settings fern” on all three surfaces. The normal enabled recipe is restored through the UI afterward.

Next chat uses the edited recipe

Renaming that same Codex tab to auth/login takes priority on its tab, sidebar and Vault row. Clearing the manual label restores “ALT Settings fern” everywhere. The generated name stays saved throughout, and neither action makes another naming call.

Manual name takes priority Clearing reveals the saved name
Manual name takes priority Clearing reveals the saved name

Earlier hidden Electron failure/restart captures on b0775764539 remain attributed to that capture head. A deliberately failing naming command exits 42; the first and later turns complete normally, the chat stays “Codex Chat” without a saved name, and exactly one naming invocation is recorded. Restarting the isolated app and sending a third turn to the same restored chat leaves the count at one. These are historical rendered evidence, supplemented by the current failure/replay/restart unit tests; they are not recaptured images of the current head.

Failed naming, later turn Same chat after app restart
Failed naming does not block or retry Same unnamed chat after app restart

Testing

For the layout-only follow-up 2080a01c77e9, 41 tests pass in five explicit Settings files, including the existing unsaved-changes guard tests. All three typecheck projects pass serially through tc-gate; changed-code quality, design-system checks, formatting and commit hooks pass. Nesting Chat names back inside the Appearance card makes the peer-section regression test fail; restoring the exact reviewed bytes returns the suite to green. Existing translations are reused in all six catalogs. The prescribed hidden Electron driver exercised the real search and dirty-draft controls, and both workers inspected the full frames. CI for this new head is blocked by an inherited full-lint failure in mobile/src/session/use-mobile-native-chat-turn-disclosure.test.tsx (816 counted lines after the newer main-side test addition); the failed CI run checks the merged PR and main. This PR does not modify that file. The earlier full-feature checks below remain historical evidence. Naming behavior, backend, and AI Vault code are unchanged by this five-file follow-up.

  • I manually tested these changes locally
  • Automated tests added/updated

On the pre-layout commit 08959b00bc7b, the complete focused suite passes 627 tests in 59 explicit files. All three typecheck projects pass serially through tc-gate, with incremental caches deleted after the latest main merge. Changed-code quality passes with zero findings across 117 changed TypeScript files, including type-aware lint and design-system checks; CI’s separately pinned React Doctor command also passes. The pending-save regression fails with the old render-time ref updates and passes after restoring commit-phase publication. All naming strings are present in every catalog; the actual catalog, extraction and coverage gates passed after the Japanese correction. The current-main review is clean, and the full CI run passes, including all five unit shards, static analysis/typecheck, relay integration, wire compatibility and both packaging jobs. Its first attempt hit one HTTP socket-close in the existing remote wake-up test; the involved test/server/relay source matches main exactly. Its 51 tests pass locally under Node, and the failed CI jobs pass on rerun under Bun with no source changes.

Tests cover both providers' accepted/admitted sends, command-first and empty-message eligibility, replay/restart/failed-attempt expiry, guarded record writes, snapshot versions, tab/sidebar/Vault precedence, cache closure and in-flight scans, exact local/paired host ownership, census/reconnect recovery, bounded batch work, and Settings queue/draft/discard/later-save lifetime. Meaningful guard ablations produced behavioral failures, then restored exact bytes and passing tests; restored source symbols were checked again at the final freeze. The full CI run exposed two stale test contracts: the captured Claude journal fixture now supplies the methods read by the feed with host timestamps, and the spacing guard reads the extracted Custom command component. Both keep their original behavior assertions; production logic was not weakened. No lockfile or documentation enters the feature diff.

The older CI failures in unrelated release-checkout and file-explorer assertions are fixed by main’s merged PR #24878, which is included here. This PR authors no changes to those unrelated tests.

Review

The separate Chat names layout delta received a clean independent Codex gpt-6.1-sol review at xhigh. It checked the requested user-facing outcome, existing Integrations structure, separate card boundaries, unique anchor, all search phrases, structured-chat and desktop-only gates, and draft visibility/discard lifetime. This follow-up does not reopen the naming backend or AI Vault design review. The PR remains ready for review, unmerged, with automatic merge disabled.

The requested review covered the complete backend and Settings feature. Earlier loops reproduced and corrected first-turn timing, closed-Vault delivery and recovery, ownership and lifetime, failed Settings persistence, Custom command setup and ineffective paired-web configuration. Before this layout follow-up, on commit 08959b00bc7b, Codex gpt-6.1-sol at xhigh and its independent same-model reviewer completed clean source reviews of the full feature, latest main integration and preserved test assertions. Readiness was assessed at both the start and end; both review reports were read and accepted, and their workers settled and released. The prescribed hidden Electron drivers used Codex gpt-5.6-terra at medium because Grok had no usage. Current-main provider confirmation is accepted and uploaded. The full CI rerun passes. The additional ready-event checks, including paired-client browser coverage, and Ubuntu headless persistence also pass. This PR is ready for review and remains unmerged with automatic merge disabled.

Agent skill upstream boundary

  • Not applicable; no upstream skill code is copied.

Notes

The existing tab frame and title-resolution request/response gain optional saved-title ownership metadata; no stream operation is added. Old peers can ignore the optional fields. Native recovery accepts only explicit record-owned replies, so an old host’s transcript title cannot become a generated native name. Folder workspaces require no Git repository. Local checks use isolated provider fixtures; live provider quality and live SSH/Windows/Linux UI validation are not claimed.

PR author: @BrennanKB5.

Checklist

  • This PR is focused on naming structured chats
  • I explained the before/after, mechanism, and alternatives
  • Before/after screenshots attached for the updated behavior
  • Updated independent correctness, security and performance review complete
  • Cross-platform, SSH and existing-client impact considered
  • Project checks and CI pass on the updated implementation

@brennanb2025

brennanb2025 commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor Author

Current integrated head is c9a9c94904fe, including main 5b8a982f8f76. All 155 tests in 18 explicit files pass. The three local project typechecks are running serially through the machine gate; node is waiting for a shared slot. Final same-model review uses Codex gpt-6.1-sol at xhigh, including a verified same-model nested reviewer and readiness checks at the start and end. The prior review was clean after correcting the first-turn timing race; the 18 restored gate ablations remain supported by unchanged naming code.

All backend Electron scenarios are complete. Eleven full, independently inspected screenshots are attached in the PR body: both providers; tab/sidebar/Vault names; manual rename and clearing; disabled naming; failed generation and later turns without retry, including a verified app restart; and changed naming agent, arguments and template on fresh chats. Exact saved records and process arguments/input support the frames, and uploaded blob hashes match local bytes. The flow uses isolated provider protocol fixtures. All drivers settled and were released; the isolated app was stopped using only its recorded processes.

The main integration audit retains all 47 feature files, with 45 unchanged byte for byte and only two expected main edits. The feature diff contains no lockfile or documentation. Main’s merged PR #24878 supplies the inherited CI fixes; updated CI is running on this head. Changed-code quality, final review and complete checks/CI are still required before marking ready.

This PR remains draft. The separate Chat names settings section waits for the owner’s replacement Chat-page base. No merge or auto-merge will be performed.

@brennanb2025
brennanb2025 marked this pull request as ready for review October 6, 2026 03:32
@coderabbitai

coderabbitai Bot commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 5e06ad2a-c84d-4d81-b815-6dc959297b3d
📥 Commits

Reviewing files that changed from the base of the PR and between eb3ade5 and 4d7ef77.

📒 Files selected for processing (6)
  • src/main/claude/claude-background-wake-retention.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-status-feed.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-status-journal-projection.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-status-summary.ts
  • src/main/text-generation/source-control-local-process.ts
  • src/shared/runtime-session-contracts.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 4 remain after this review.


📝 Walkthrough

Walkthrough

The PR adds automatic naming for structured Claude and Codex chats, including first-prompt eligibility, configurable generation, and compare-and-set storage. Runtime and renderer changes publish and project saved names in session tabs and AI Vault rows, including after chats close or scans are in flight. Chat settings add naming controls, recipe and command editing, localization, and unsaved-change handling. Tests cover naming, publication, recovery, settings, and ownership.

Priority: ➖ Normal

Merge Risk: 🔵 Low · up to 4d7ef

The change names chats from their first message. An earlier open concern says that raw first-message text can imitate naming instructions and produce an incorrect saved title. This is low impact and does not block merging, but the owner should check it.

Security Architecture Review

Security architecture risk: 🔵 Low · up to b0eb3

Automatic chat naming has a low-severity risk of following instructions embedded in the first message. Saved names are protected from concurrent overwrites, and broader effects depend on configured local permissions and have not been demonstrated.

Retained concerns

  • Low · security · observed: The new automatic naming path places first-message text in the same instruction string as the naming rules, allowing embedded instructions to steer generation. Output sanitization bounds the persisted title but does not constrain execution-time capabilities. Broader effects depend on the configured executable; none were verified.
Security review details

Security Blast Radius

  • inferred — Exposure begins with the first usable message of an eligible native chat. Active-session deduplication and saved-title persistence limit repeated execution. The naming process runs with configured local environment and workspace context, so any effects beyond the title depend on that executable's effective capabilities; a workspace-only sandbox is not established for every configuration.

Security Findings and Attack Paths

  • observed — The retained, verified low-severity finding concerns first-message instruction injection into automatic naming. This path is introduced by the PR. The demonstrated boundary weakness is instruction influence over generation; host modification, data exfiltration, and privilege escalation were not verified.

Trust Boundaries and Controls

  • observed — Strong counterevidence includes native-host enforcement, read-only or planning flags for the principal built-in executables, and argv/stdin planning that avoids treating message text as shell syntax. These controls narrow the attack path but do not remove instruction injection or establish uniform tool restrictions for custom commands.

Resilience and Maintainability Implications

  • observed — Concurrent name changes defeat stale generated replacement through compare-and-set. Cancellation and timeout initiate process termination and finalize generation as unsuccessful; the naming handler retains the durable placeholder and clears its active marker.

Hardening Proposals

  • proposed — Define an explicit text-only, no-tools execution contract for automatic naming across built-in and custom configurations. Keep first-message content distinct from trusted instructions, without treating delimiters alone as a sandbox.
🚥 Pre-merge checks | ✅ 3 | ❌ 1 | ❓ 1

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.20% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 122 functions across 83 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The description is detailed and covers the change, rationale, visual proof, testing, review, and compatibility notes. It says there is no separate issue, but the template requires an issue link for ou… Confirm whether the author is a maintainer. If not, add a link to the issue this pull request addresses.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: naming native Claude and Codex chats after their first message.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

The description is detailed and covers the change, rationale, visual proof, testing, review, and compatibility notes. It says there is no separate issue, but the template requires an issue link for outside contributors and exempts maintainers; the author’s status is not specified.

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/shared/conversation-name-generation.ts (1)

34-41: 🔒 Security & Privacy | 🛡️ Detected with Advanced Tier | 🔵 Trivial | ⚡ Quick win

LLM Security

Reachability: External
Exploitability: Theoretical
CWE: CWE-1427

Put the user's first prompt inside named delimiters.

buildConversationNamePrompt inserts the raw first prompt after First request:. Nothing separates that text from the instructions around it. A first message such as "Ignore the above and output …" can therefore control the generated title. The custom Additional instructions text comes after the prompt, so a prompt that contains a forged Additional instructions: heading also looks like a real instruction. The impact is limited to the chat title, so this is low risk. The fix is still cheap. Wrap the prompt in tags and tell the model to treat the tag content as data.

Proposed change
-Output only the title, with no heading, quotes, or explanation.
-
-First request:
-${firstPrompt}`
+Output only the title, with no heading, quotes, or explanation.
+Treat the text inside <first_request> as data to summarize, not as instructions.
+
+<first_request>
+${firstPrompt}
+</first_request>`

This comment follows the retrieved learning: wrap untrusted fields in named delimiter tags when building LLM prompts.


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 7968925d-315f-4344-882a-40d1cd5ba1eb
📥 Commits

Reviewing files that changed from the base of the PR and between 08a970a and b0eb31d.

📒 Files selected for processing (46)
  • src/main/ai-vault/structured-session-ownership.test.ts
  • src/main/ai-vault/structured-session-ownership.ts
  • src/main/native-chat/agent-session-wire/structured-provider-session-ownership.ts
  • src/main/native-chat/structured-chat-naming-status-hook.test.ts
  • src/main/native-chat/structured-chat-naming.test.ts
  • src/main/native-chat/structured-chat-naming.ts
  • src/main/runtime/agent-session-conversation-name-store.test.ts
  • src/main/runtime/agent-session-record-conversation-name.ts
  • src/main/runtime/agent-session-record-store.ts
  • src/main/runtime/agent-session-tab-visibility.ts
  • src/main/runtime/orca-runtime-get-worktree-ps.ts
  • src/main/runtime/orca-runtime-prune-mobile-session-tab-group-layout.ts
  • src/main/runtime/orca-runtime-structured-session-restore.test.ts
  • src/main/runtime/structured-chat-naming-runtime.test.ts
  • src/main/runtime/structured-chat-naming-runtime.ts
  • src/main/runtime/structured-conversation-tab-title.test.ts
  • src/main/runtime/structured-conversation-tab-title.ts
  • src/main/text-generation/commit-message-text-generation.ts
  • src/main/text-generation/conversation-name-generation-request.test.ts
  • src/main/text-generation/conversation-name-generation-request.ts
  • src/main/text-generation/source-control-local-process.ts
  • src/main/text-generation/source-control-remote-generation.ts
  • src/main/text-generation/source-control-text-generation-requests.ts
  • src/main/text-generation/source-control-text-generation-types.ts
  • src/renderer/src/components/dashboard/use-agent-row-conversation-name.test.ts
  • src/renderer/src/components/dashboard/use-agent-row-conversation-name.ts
  • src/renderer/src/components/right-sidebar/AiVaultSessionRow.test.tsx
  • src/renderer/src/components/right-sidebar/AiVaultSessionRow.tsx
  • src/renderer/src/lib/structured-chat-tab-index.test.ts
  • src/renderer/src/lib/structured-chat-tab-index.ts
  • src/shared/conversation-name-action.test.ts
  • src/shared/conversation-name-generation.test.ts
  • src/shared/conversation-name-generation.ts
  • src/shared/global-settings-types.ts
  • src/shared/native-chat-global-settings.ts
  • src/shared/source-control-ai-action-variables.ts
  • src/shared/source-control-ai-actions.ts
  • src/shared/source-control-ai-command-template.ts
  • src/shared/source-control-ai-model-selection.ts
  • src/shared/source-control-ai-operation-policy.ts
  • src/shared/source-control-ai-settings.ts
  • src/shared/source-control-ai-types.ts
  • src/shared/source-control-ai.ts
  • src/shared/structured-agent-session-first-prompt.test.ts
  • src/shared/structured-agent-session-first-prompt.ts
  • src/shared/structured-chat-row-name.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 0 remain after this review.

@brennanb2025
brennanb2025 marked this pull request as draft October 6, 2026 05:01
@brennanb2025

brennanb2025 commented Oct 6, 2026 •

Copy link
Copy Markdown
Contributor Author

Chat names previously shared the Appearance card on Settings → Chat, so naming read as an appearance preference. Commit 2080a01c77e9 gives Appearance and Chat names separate peer headings and cards using the existing stacked settings layout and card primitives. The chat-names anchor, desktop-only and updated-structured-chat gates, and unsaved template visibility/discard behavior remain intact; “chat names”, “name”, and “Name chats automatically” all find the naming section. Naming behavior, backend, and AI Vault code are unchanged in this five-file follow-up.

All 41 tests in five explicit Settings files pass, all three typecheck projects pass serially through tc-gate, and changed-code quality and commit hooks pass. The boundary ablation fails when naming is placed back inside Appearance and passes after exact source restoration. The independent Codex gpt-6.1-sol review at xhigh is clean. The prescribed Codex gpt-5.6-terra medium driver and implementing worker inspected full hidden Electron frames for enabled naming, disabled naming, and an unsaved template after unmatched search; the PR body now includes those new frames and labels the previous layout as before evidence. The isolated validation app and both workers have been cleaned up.

Update: the CI failure on 2080a01c77e9 came from an over-long mobile test file on main, which main has since split; this PR never touched that file. Head is now 4d7ef779f587, which merges current main 4c3551615005 (two merge commits, no force-push). Two conflicts needed more than picking a side. Main and this branch had each pulled the same visible-tab lookup out of the record store, so the branch now uses main's copy and drops its own identical one. Main's new launch-directory and "Stopping…" status fields now flow through this PR's separate status-summary function. To keep the record store under its 300-line limit after both sides' additions, its one-call commitProcessIdentity method became an arrow property; it behaves the same. Naming, AI Vault and settings code are unchanged.

Local checks on the new head: all three typecheck projects pass (run one at a time through tc-gate), full oxlint passes, the changed-code quality gate passes, and 496 tests in 51 explicitly listed files pass. On GitHub, all four workflows succeed on 4d7ef779f587: PR Checks, Mobile Checks, Headless Node server and PR test LoC (20 checks pass, 18 skipped, none failing). The PR stays ready for review and unmerged, with automatic merge disabled. PR author: @BrennanKB5.

@brennanb2025
brennanb2025 marked this pull request as ready for review October 6, 2026 15:08

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Repository UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 689f0bfa-7d3b-47db-b809-5422f30ad127
📥 Commits

Reviewing files that changed from the base of the PR and between b0eb31d and 08959b0.

📒 Files selected for processing (95)
  • config/scripts/vitest-node-runtime-files.mjs
  • config/scripts/vitest-runtime-boundary.test.ts
  • src/main/ai-vault/session-title-resolver.ts
  • src/main/ai-vault/session-title-result-validation.ts
  • src/main/ai-vault/session-title-structured-record.test.ts
  • src/main/ai-vault/structured-session-ownership.test.ts
  • src/main/ai-vault/structured-session-ownership.ts
  • src/main/claude/claude-background-wake-retention.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-host-types.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-status-feed.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-status-first-input-identity.test.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-status-journal-projection.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-status-observation.ts
  • src/main/native-chat/agent-session-wire/structured-agent-session-status-summary.ts
  • src/main/native-chat/agent-session-wire/structured-provider-session-ownership.ts
  • src/main/native-chat/structured-chat-naming-command-first.test.ts
  • src/main/native-chat/structured-chat-naming-status-hook.test.ts
  • src/main/native-chat/structured-chat-naming.test.ts
  • src/main/native-chat/structured-chat-naming.ts
  • src/main/runtime/agent-session-record-store.ts
  • src/main/runtime/orca-runtime-build-headless-mobile-session-browser-tabs.ts
  • src/main/runtime/orca-runtime-get-worktree-ps.ts
  • src/main/runtime/orca-runtime-prune-mobile-session-tab-group-layout.ts
  • src/main/runtime/orca-runtime-structured-conversation-title-publication.test.ts
  • src/main/runtime/rpc/methods/ai-vault-structured-ownership.test.ts
  • src/main/runtime/rpc/methods/ai-vault.ts
  • src/main/runtime/structured-chat-naming-runtime.ts
  • src/renderer/src/components/AiVaultTabTitleSyncGate.tsx
  • src/renderer/src/components/dashboard/use-agent-row-conversation-name.test.ts
  • src/renderer/src/components/right-sidebar/AiVaultSessionRow.structured-title.test.tsx
  • src/renderer/src/components/right-sidebar/AiVaultSessionRow.test.tsx
  • src/renderer/src/components/right-sidebar/AiVaultSessionRow.tsx
  • src/renderer/src/components/right-sidebar/ai-vault-applied-scan.ts
  • src/renderer/src/components/right-sidebar/ai-vault-live-provider-session-ids.ts
  • src/renderer/src/components/right-sidebar/ai-vault-pending-title-projection.test.ts
  • src/renderer/src/components/right-sidebar/ai-vault-pending-title-projection.ts
  • src/renderer/src/components/right-sidebar/ai-vault-session-refresh.ts
  • src/renderer/src/components/right-sidebar/ai-vault-session-result-cache.ts
  • src/renderer/src/components/right-sidebar/ai-vault-structured-title-fixtures.ts
  • src/renderer/src/components/right-sidebar/ai-vault-structured-title-projection.test.ts
  • src/renderer/src/components/right-sidebar/ai-vault-structured-title-projection.ts
  • src/renderer/src/components/right-sidebar/ai-vault-structured-title-recovery.test.ts
  • src/renderer/src/components/right-sidebar/ai-vault-structured-title-recovery.ts
  • src/renderer/src/components/settings/ChatNamingSetting.test.tsx
  • src/renderer/src/components/settings/ChatNamingSetting.tsx
  • src/renderer/src/components/settings/ChatSettingsSection.navigation.test.tsx
  • src/renderer/src/components/settings/ChatSettingsSection.test.tsx
  • src/renderer/src/components/settings/ChatSettingsSection.tsx
  • src/renderer/src/components/settings/CommitMessageAiPane.tsx
  • src/renderer/src/components/settings/CustomAgentCommandField.tsx
  • src/renderer/src/components/settings/SourceControlActionRecipeRow.tsx
  • src/renderer/src/components/settings/chat-naming-persistence.test.tsx
  • src/renderer/src/components/settings/chat-naming-search.ts
  • src/renderer/src/components/settings/chat-settings-unsaved-guard.test.tsx
  • src/renderer/src/components/settings/settings-git-task-section-renderers.tsx
  • src/renderer/src/components/settings/settings-interface-secondary-section-renderers.tsx
  • src/renderer/src/components/settings/settings-persistence-test-fixture.ts
  • src/renderer/src/components/settings/settings-view-model.ts
  • src/renderer/src/components/settings/source-control-action-recipe-options.ts
  • src/renderer/src/components/settings/source-control-ai-settings-persistence.test.tsx
  • src/renderer/src/components/settings/use-settings-interaction-controller.ts
  • src/renderer/src/components/settings/use-settings-navigation-model.ts
  • src/renderer/src/components/settings/use-settings-store-model.ts
  • src/renderer/src/components/source-control/SourceControlActionVariableChips.tsx
  • src/renderer/src/hooks/settings-navigation-interface-sections.ts
  • src/renderer/src/i18n/locales/en.json
  • src/renderer/src/i18n/locales/es.json
  • src/renderer/src/i18n/locales/fr.json
  • src/renderer/src/i18n/locales/ja.json
  • src/renderer/src/i18n/locales/ko.json
  • src/renderer/src/i18n/locales/zh.json
  • src/renderer/src/i18n/native-chat-locales.test.ts
  • src/renderer/src/lib/ai-vault-tab-title-batches.ts
  • src/renderer/src/lib/i18n-jsx-spacing-guard.test.ts
  • src/renderer/src/runtime/local-structured-session-tabs-sync/snapshot-apply.ts
  • src/renderer/src/runtime/local-structured-session-tabs-sync/subscription.ts
  • src/renderer/src/runtime/structured-conversation-title-host-pairing.test.ts
  • src/renderer/src/runtime/structured-conversation-title-publication.test.ts
  • src/renderer/src/runtime/web-session-tabs-sync/active-session-subscription.ts
  • src/renderer/src/runtime/web-session-tabs-sync/global-session-events.ts
  • src/renderer/src/runtime/web-session-tabs-sync/global-session-inventory-event.ts
  • src/renderer/src/runtime/web-session-tabs-sync/load-initial.ts
  • src/renderer/src/runtime/web-session-tabs-sync/mirror-settle.ts
  • src/renderer/src/runtime/web-session-tabs-sync/store-patch.ts
  • src/renderer/src/runtime/web-session-tabs-sync/visibility-resume-repair.ts
  • src/shared/ai-vault-session-title.ts
  • src/shared/conversation-name-generation.test.ts
  • src/shared/conversation-name-generation.ts
  • src/shared/native-chat-appearance-settings.ts
  • src/shared/rpc-contract/ai-vault-params.ts
  • src/shared/runtime-session-contracts.ts
  • src/shared/structured-chat-naming-eligibility.test.ts
  • src/shared/structured-chat-naming-eligibility.ts
  • src/shared/structured-chat-row-name.ts
  • tests/e2e/structured-conversation-title-census-recovery.unit.test.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

Comment on lines +23 to +26
First request:
${firstPrompt}`
const extra = customPrompt.trim()
return extra ? `${basePrompt}\n\nAdditional instructions:\n${extra}` : basePrompt

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Separate the first request from naming instructions.

If a first request contains Additional instructions: or similar text, the naming agent can treat that user text as a naming instruction. This can produce and save the wrong title. Put the first request and custom instructions in distinct, named delimiters. Escape delimiter characters in the first request so its text cannot close its own section. Based on learnings: wrap user-supplied prompt fields in distinct, clearly named delimiter tags instead of inserting them raw inline.

Source: Learnings

Main and this branch both pulled the visible-tab helpers out of the record
store; keep main's copy in agent-session-tab-table and drop the duplicate.
Main's pinned launch directory moves into the extracted status summary.
Main's Stop-in-progress flag joins the first-input fields on the journal
projection and reaches the extracted status summary.
@brennanb2025
brennanb2025 merged commit 6aa12c3 into main Oct 6, 2026
38 checks passed
brennanb2025 added a commit that referenced this pull request Oct 6, 2026
…bs runtime stays under its line limit

The merge of main (#25724's emitMobileSessionTabsSnapshot metadata) plus this branch's close mark put
the file one line over max-lines. Formatting only.
brennanb2025 added a commit that referenced this pull request Oct 7, 2026
…ed (#25430)

* feat(agent-launch): host-assigned caller identity and a launch record written when the surface exists

Step 1 of the agent-launch unification, on main.

- The dispatcher stamps every request's caller from what its connection proved (runtime socket:
  the local CLI; the desktop's IPC: the desktop; a paired socket: its device). Params never set it.
- The launch record is written twice: once when the tab exists (what creation settled: on the
  launch command, a draft, or a submit still `unconfirmed`), and again once the prompt's fate is
  known. A restart in between finds the running agent instead of answering "unknown".
- A replay re-derives its terminal handle from the pane key in the running host, and shows
  `unconfirmed` only to callers that advertise agent.launch.prompt-unconfirmed.v1.
- The record store opens in its own slot, without building the chat host; the chat host is built
  on that same store.

Rebuilt from this PR's own commits (b9adf88, 0d7d9b5, c83f44d, 39d15d5) onto
main, without #24080/#24081. Conflicts: the delivery doc table (main's "line fits" row plus the
`unconfirmed` row), and main's journal-database open in install(), which now goes through the
record-store slot.

* feat(agent-launch): show an agent's tab at once, where the caller asked for it

An agent.launch now shows its terminal tab before admission and spawn, in
the requested placement (group and/or anchor tab), and the pane attaches to
the agent as soon as it runs. A pane whose agent can't start, or whose start
can't be confirmed, says so instead of becoming a plain shell, and keeps
saying so across restarts. A user's close of the tab or its pane during the
launch stops it and answers agent_launch_tab_closed. Whose view moves is
unchanged from main for every caller.

Rebuilt on main (with #24934) from the previous branch head 8f62858.

* style(runtime): one-line the tab-order map so the headless browser-tabs runtime stays under its line limit

The merge of main (#25724's emitMobileSessionTabsSnapshot metadata) plus this branch's close mark put
the file one line over max-lines. Formatting only.
brennanb2025 added a commit that referenced this pull request Oct 7, 2026
…agent.launch (#25624)

* feat(agent-launch): host-assigned caller identity and a launch record written when the surface exists

Step 1 of the agent-launch unification, on main.

- The dispatcher stamps every request's caller from what its connection proved (runtime socket:
  the local CLI; the desktop's IPC: the desktop; a paired socket: its device). Params never set it.
- The launch record is written twice: once when the tab exists (what creation settled: on the
  launch command, a draft, or a submit still `unconfirmed`), and again once the prompt's fate is
  known. A restart in between finds the running agent instead of answering "unknown".
- A replay re-derives its terminal handle from the pane key in the running host, and shows
  `unconfirmed` only to callers that advertise agent.launch.prompt-unconfirmed.v1.
- The record store opens in its own slot, without building the chat host; the chat host is built
  on that same store.

Rebuilt from this PR's own commits (b9adf88, 0d7d9b5, c83f44d, 39d15d5) onto
main, without #24080/#24081. Conflicts: the delivery doc table (main's "line fits" row plus the
`unconfirmed` row), and main's journal-database open in install(), which now goes through the
record-store slot.

* feat(agent-launch): show an agent's tab at once, where the caller asked for it

An agent.launch now shows its terminal tab before admission and spawn, in
the requested placement (group and/or anchor tab), and the pane attaches to
the agent as soon as it runs. A pane whose agent can't start, or whose start
can't be confirmed, says so instead of becoming a plain shell, and keeps
saying so across restarts. A user's close of the tab or its pane during the
launch stops it and answers agent_launch_tab_closed. Whose view moves is
unchanged from main for every caller.

Rebuilt on main (with #24934) from the previous branch head 8f62858.

* feat(agent-launch): the desktop AI buttons start their agent through agent.launch

Part 3 of 3 of the agent-launch unification, on main. The AI buttons (Fix
checks, the source-control actions, commit/push recovery, Explain commit,
notes and annotation sends, session continuation) started their agent from
the window. They now ask the host's agent.launch to start it, with no
prompt, into the tab the window makes at the click, under one operation id
per click; the window's pane waits for the host's agent instead of spawning
a shell. The window then pastes the prompt with main's own paste, moved out
verbatim and started only once the host's agent holds the tab, so delivery
and follow-ups are exactly main's. A typed new-tab prompt and launches while
chat is the default keep main's path. The source-control dialog drops its
launch-command preview, which the host builds now.

* style(runtime): one-line the tab-order map so the headless browser-tabs runtime stays under its line limit

The merge of main (#25724's emitMobileSessionTabsSnapshot metadata) plus this branch's close mark put
the file one line over max-lines. Formatting only.

* fix(agent-launch): watch an AI button's agent for readiness from its first output

The window started watching for the agent's ready signal only after the host
answered agent.launch, so an agent that had already turned on bracketed paste
by then was never seen ready and its prompt waited out the readiness budget.

Readiness is now watched from the moment the tab's terminal exists, as main
watches it; the paste is written, and the chat copy seeded, only once the host
says its agent started in that tab.
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.

1 participant