App-server TUI mention picker truncates $ skill candidates to 8 items instead of allowing scroll

Resolved 💬 2 comments Opened Mar 28, 2026 by jasontan656 Closed Mar 28, 2026

What version of Codex CLI is running?

117

What subscription do you have?

200usd

Which model were you using?

5.4 high

What platform is your computer?

wsl linux

What terminal emulator and version are you using (if applicable)?

_No response_

What issue are you seeing?

Title
App-server TUI mention picker truncates $ skill candidates to 8 items instead of allowing
scroll

Summary
After upgrading to codex-cli 0.117.0, the $ mention picker in the app-server TUI does not
expose the full skill list. The issue is not that skills fail to load. Skills remain
available and can still be invoked by typing their names directly, but the picker itself
truncates the candidate set to 8 items before rendering. This makes keyboard navigation
impossible beyond the first 8 results and creates the false impression that most skills
are missing.

This appears to be a UI logic bug rather than an intended product decision. Limiting
visible rows to 8 is reasonable. Truncating the actual candidate set to 8 is not.

Observed user-facing behavior

  • Typing $ only shows a small fixed list, typically GitHub, Gmail, and the first few Dev-*

skills.

  • Arrow-key navigation cannot move beyond those visible 8 entries.
  • Custom skills such as $Functional-BrainStorm still resolve immediately when typed by

name.

  • OpenAI-provided skills such as skill-creator and skill-installer also appear to be

“missing” from the picker unless their names are typed or the query narrows enough.

Why this is clearly a bug
The system is successfully loading the skills. The failure is in the mention picker
display and selection path.

The strongest user-visible proof is:

  1. Hidden skills can still be mentioned directly by typing $SkillName.
  2. The picker never exposes more than 8 items.
  3. Arrow navigation cannot reach any item beyond those 8.

That combination means the candidate set is being truncated before navigation and
rendering, rather than the UI merely showing an 8-row viewport over a larger list.

Root cause
In the app-server TUI source, SkillPopup::filtered() truncates the mention results to
MAX_POPUP_ROWS.

Relevant code paths:

  • codex-rs/tui_app_server/src/bottom_pane/popup_consts.rs
  • codex-rs/tui_app_server/src/bottom_pane/skill_popup.rs
  • codex-rs/tui_app_server/src/bottom_pane/chat_composer.rs

Key details:

  • MAX_POPUP_ROWS is defined as 8.
  • SkillPopup::filtered() sorts the full mention set, then executes

out.truncate(MAX_POPUP_ROWS).

  • ScrollState and the shared popup renderer already support scrolling within a bounded

visible window.

  • Therefore the truncation is redundant and harmful.

The likely intended design is:

  • Keep the visible popup height capped to 8 rows.
  • Keep the full filtered result set intact.
  • Use ScrollState to navigate and render a sliding 8-row window.

That is how other list/popup surfaces in the same TUI already behave.

Why the visible results skew toward GitHub/Gmail and Dev skills
The mention list is assembled from plugins, skills, and apps.

Sorting behavior in chat_composer.rs gives plugins a higher priority (sort_rank = 0) than
skills (sort_rank = 1). After that, items are sorted alphabetically. Because the picker
then truncates to the first 8 items, the visible list is dominated by:

  • plugin-backed items such as GitHub/Gmail
  • alphabetically early skill names such as Dev-*

This explains why users incorrectly conclude that Functional-, Meta-, Workflow-*, and
some built-in skills are missing.

Evidence that loading is not the issue
The upstream loader parses skill frontmatter permissively. It does not reject extra top-
level YAML fields in a way that would explain this symptom.

Also, the chat state still contains the skills. The failure occurs downstream in the popup
filtering/sorting/truncation path.

Minimal fix
Remove the candidate truncation in SkillPopup::filtered().

Keep these behaviors unchanged:

  • MAX_POPUP_ROWS = 8 as the visual height limit
  • existing sort order
  • existing ScrollState navigation
  • existing popup rendering contract

In other words:

  • limit visible rows to 8
  • do not limit the underlying candidate list to 8

Local validation
I implemented the minimal fix locally by removing the early truncation in:

  • codex-rs/tui_app_server/src/bottom_pane/skill_popup.rs

I also updated tests to reflect the correct behavior:

  • the filtered result set is no longer capped to 8
  • popup height remains capped to 8 visible rows
  • keyboard navigation can move to items beyond the first page

Local test result:

  • cargo test -p codex-tui skill_popup --lib
  • Result: passed

This restored expected behavior in practice:

  • the $ picker still shows an 8-row popup
  • arrow keys can now reach items beyond the first 8
  • previously hidden skills are now discoverable by navigation rather than only by manual

typing

Why this should be fixed upstream
This issue creates a misleading UX failure:

  • users believe custom skills are broken or unsupported in 0.117.0
  • OpenAI-provided skills also appear missing
  • the system still works underneath, but the picker makes discovery and selection

unreliable

Because the bug sits in a default TUI workflow and affects both user skills and built-in
skills, it is likely to impact many users who rely on the $ picker rather than exact-name
typing.

Recommended upstream action

  1. Remove the out.truncate(MAX_POPUP_ROWS) call from SkillPopup::filtered().
  2. Keep MAX_POPUP_ROWS as a viewport limit only.
  3. Add or update tests to enforce:
  • full filtered candidate preservation
  • 8-row visual cap
  • navigation beyond the first visible page
  1. Review whether similar premature truncation exists in adjacent popup components, but

treat that as a separate audit rather than bundling unrelated behavior changes into
this fix.

  • Confirmed that skills were still installed and mentionable by exact name.
  • Confirmed that the picker never exposed more than 8 entries and could not navigate

beyond them.

  • Inspected upstream TUI app-server source.
  • Found MAX_POPUP_ROWS = 8 and out.truncate(MAX_POPUP_ROWS) in skill_popup.rs.
  • Confirmed that shared scroll/render infrastructure already supports longer result sets

with an 8-row viewport.

  • Implemented a local minimal patch removing the truncation.
  • Added/updated tests.
  • Rebuilt locally and verified behavior was restored.

Codex session id: "019d33a5-9976-73f3-b05f-6fb0802c5c13"
timestamp: 2026-03-28 18:37:32

What steps can reproduce the bug?

Uploaded thread: 019d33a5-9976-73f3-b05f-6fb0802c5c13

What is the expected behavior?

_No response_

Additional information

_No response_

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗