Codex App: threads created by codex exec can't be pinned or moved to a sidebar section
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.4k
- PR merge metrics
- PR metrics pending
Description
What version of the Codex App are you using (From “About Codex” dialog)?
26.908.70816 (bundled codex-cli 0.154.0-alpha.6.2)
What subscription do you have?
Pro
What platform is your computer?
Darwin 25.6.0 arm64 arm
What issue are you seeing?
A thread that was created by codex exec shows up under Recent in the Codex App sidebar, but it can't be pinned or moved into a custom section. Choosing Pin, or dragging it into a section, moves it for a moment and then it jumps back to Recent. No error is shown. Every other thread in the same sidebar pins and moves normally.
The move itself succeeds. After the attempt, the thread's row in state_5.sqlite has thread_section_id set to the target section (or the Pinned section). The thread just never appears in that section's list.
The cause is the section listing request. To read a section's members, the app calls thread/list with sectionId, sortKey: "section_position" and useStateDbOnly: true, but without sourceKinds. When sourceKinds is missing or empty, the app server falls back to INTERACTIVE_SESSION_SOURCES (codex-rs/app-server/src/filters.rs), which is cli, vscode, atlas and chatgpt. A thread started by codex exec is stored with source = "exec", so it is filtered out of every section, including Pinned. It still appears under Recent because the app already has the conversation loaded, so the only visible effect is that section placement never sticks.
What steps can reproduce the bug?
In the app:
- Start a thread with
codex execin the sameCODEX_HOMEthe app uses (for example as the target of a heartbeat automation), so it appears in the sidebar under Recent. - Pin it, or drag it into a custom section.
- It returns to Recent.
Directly against the app server, using a thread whose row has source = 'exec' and thread_section_id = <section>:
// thread/list request without sourceKinds, the same shape the app sends
{"limit":100,"modelProviders":[],"sectionId":"<section>","sortKey":"section_position","useStateDbOnly":true}
// -> data: []
// same request plus sourceKinds
{"limit":100,"modelProviders":[],"sectionId":"<section>","sortKey":"section_position","useStateDbOnly":true,"sourceKinds":["cli","vscode","exec","appServer"]}
// -> data: [ the exec thread ]
Changing only that row's source from exec to vscode makes the first request return the thread, and the app then pins and moves it normally.
What is the expected behavior?
Any thread the sidebar shows can be pinned or moved to a section, and stays there regardless of which surface created it.
Additional information
Either side could fix it. The app could pass an explicit sourceKinds that includes exec when listing a section. Or the app server could skip the default interactive-source filter when sectionId is given, since a thread only has a section because a user explicitly placed it there.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with codex-rs/app-server/src/filters.rs and trace the thread/list handling for sectionId, sortKey, useStateDbOnly, and sourceKinds. Reproduce the two listed requests with an exec thread, then verify that a thread shown in the sidebar remains in its pinned or custom section after the relevant filtering behavior is corrected.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- backend-api-design
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100