Skip to content

feat(tui): add project context to session tab labels - #56799

Open
SKar-2007 wants to merge 1 commit into
anomalyco:devfrom
SKar-2007:tab-project-label
Open

SKar-2007 wants to merge 1 commit into
anomalyco:devfrom
SKar-2007:tab-project-label

Conversation

@SKar-2007

@SKar-2007 SKar-2007 commented Oct 18, 2026 •

Copy link
Copy Markdown

Issue for this PR

Closes #56749

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

With tabs.scope: global, sessions from different directories share one tab strip and their titles are often identical, so you cannot tell which tab belongs to which repo. This adds a tabs.label option to cli.json (title | project | path | directory, default title) that adds project context to tab labels without touching the stored session title.

  • project, path, and directory prefix horizontal tab titles with the project name, the ~-shortened session directory, or just the directory's final segment — the same detail text the vertical sidebar already shows on its second line, so worktree tabs get name⎇ branch: title in both layouts.
  • In path and directory mode the vertical sidebar's detail line shows the corresponding directory text instead of the bare project name. directory came out of review feedback: it tells apart packages of one repository that share both the project name and the parent path.
  • The option is also selectable in the settings dialog under Tabs, and the config docs table is updated.

The default title keeps today's rendering exactly; nothing changes unless you opt in. The prefix is composed at render time from the same sessionTabDetail logic the sidebar uses, so renames, marquee scrolling, and the rename dialog all keep operating on the real stored title.

How did you verify your code works?

bun run check from the repo root (34/34 tasks), the full packages/tui suite (1543 pass; the single failure is go-upsell-art "the art stops every frame", which also fails on clean dev), and the website validation (bun typecheck, bun run check:generated, bun run build in services/www) for the docs change. New tests: sessionTabDetailName and sessionTabLabel unit tests in session-tabs-model.test.ts (path substitution, ~-shortening, directory basename including a Windows path, empty fallbacks), a config-v2 default and settings-dialog assertion, and session-tabs-label.test.tsx, which renders the strip with two same-titled tabs and checks that project mode prefixes both, an unset option keeps titles plain, and the vertical layout keeps its detail line without prefixing titles. The component test is stable at --rerun-each 10.

Screenshots / recordings

TUI frames captured from the test renderer. Two tabs, both titled "Fix login bug", in different projects:

tabs.label: "title" (default, unchanged):

   Fix login bug                 Fix login bug

tabs.label: "project":

   opencode: Fix login bug       website: Fix login bug

tabs.label: "directory" (two packages of one repo):

   api: Fix login bug            cli: Fix login bug

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

Added by the opencode bot (AI-generated).

Related: #50228, #51759, #44589

Public API: adds the optional tabs.label cli.json setting (title | project | path | directory, default title; backwards compatible)

@github-actions

Copy link
Copy Markdown
Contributor

The following comment was made by an LLM, it may be inaccurate:

@opencode-agent opencode-agent 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.

This works as described, and I didn't find anything that should block it.

How I checked: I ran the TUI from source with tabs on and scope: global. On the base the tab shows OpenCode Drive. With this PR, tabs.label: "project" shows files: OpenCode Drive and "path" shows ~/files: OpenCode Drive. I didn't drive the vertical layout or a worktree session in the TUI; your vertical-layout test covers the first. The new and nearby tab tests pass (70 pass), and the packages/tui type check is clean. Renaming still uses the real stored title, and the scrolling and width logic handle the longer displayed title correctly.

Public API: this adds one optional key to the cli.json schema, tabs.label ("title" | "project" | "path", default "title"). It is also shown in the settings dialog. It is backwards compatible: existing configs render exactly as before.

No blocking concerns.

Related: #50228, #51759, #44589

Before

After

@callmeusdt

Copy link
Copy Markdown

Thanks for picking this up, the render-time prefix (leaving the stored title untouched) is exactly what I was after in #56749.

One gap I noticed from reading the diff. Please treat it as a suggestion, I haven't run the branch yet.

There is no way to show just the session directory's basename. project uses projectName(), which is project.name or the basename of the project's canonical root. path shows the full ~-shortened directory. For a session started in a subdirectory (monorepo package, worktree), project shows the repo name, so two tabs from different packages in the same repo look identical. path tells them apart but can eat a lot of tab width.

I've been using a plugin that rewrites the session title as a workaround, and it has three modes. Core of it:

const mode = String(ctx.options.path ?? "basename") // "basename" | "full" | "home"
const label = (dir: string) => {
  if (mode === "full") return dir
  if (mode === "home") return home && dir.startsWith(home) ? "~" + dir.slice(home.length) : dir
  return basename(dir) || dir
}
const prefix = label(sessionDirectory) + ":"

The basename mode is the one I use daily, because it is short and distinguishes directories.

Suggested change, if it fits your design: add a fourth value, e.g. tabs.label: "directory", handled next to the path case in sessionTabDetailName:

if (label === "directory" && directory) return path.basename(directory) || directory
if (label === "path" && directory) return abbreviateHome(directory, home)

That would keep title as the default and not change existing values. Happy to send this as a follow-up or a patch against your branch if you prefer.

Adds tabs.label (title | project | path | directory, default title) to cli.json. Horizontal tabs prefix the title with the same detail the vertical sidebar shows; path mode swaps the project name for the home-abbreviated session directory, and directory mode keeps just its final segment (split with the same win32/posix rule as the other path helpers). Display only; the stored session title is untouched.

Also fills the settings description the new-designs settings list now requires.
@SKar-2007

Copy link
Copy Markdown
Author

@callmeusdt pushed — tabs.label now accepts a fourth value, directory. It shows just the final segment of the session directory (split with the same win32/posix rule as the other path helpers, so Windows paths work), which is the case where two packages of one repository share both the project name and the parent path. Display behavior is otherwise identical to path: horizontal tabs prefix with it, vertical tabs use it in the detail line. Settings entry, docs table, and model tests (including a Windows path) updated.

The branch is also rebased onto latest dev, which required adding the new settings description field.

@opencode-agent opencode-agent 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.

The new commit still works as described, and I have no new concerns.

How I checked: I ran the TUI from source with tabs.scope: global and tabs.label: "directory". The horizontal tab is prefixed with the last part of the session directory (files: …). I didn't re-check project, path or the vertical layout on this head; those code paths only changed through the rebase. The affected tests pass (60 pass), and the packages/tui type check is clean.

Public API: this adds one optional key to the cli.json schema, tabs.label ("title" | "project" | "path" | "directory", default "title"). It is backwards compatible: existing configs render exactly as before.

Before

After

This branch has not been deployed

No deployments
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.

[FEATURE]: Option to show project/directory name in session tabs (horizontal and vertical)

2 participants