Repository navigation
Conversation
The assistant footer only appears on the final message of a prompt and shows one number: the time since that prompt. Intermediate tool-call turns show no footer, so there is no way to see when a turn finished or which step of a long run took the time. Add a `turn_timing` option to tui.json with two independent booleans: - `time`: when each assistant turn finished, as the time of day if today and the date followed by the time otherwise (Locale.todayTimeOrDateFirst, e.g. `10/4/2026 11:26 PM`). Locale.todayTimeOrDateTime keeps its time-then-date order for its existing callers. - `duration`: how long each turn took (created -> completed). The final turn keeps the existing total since the prompt and labels it `total`, so both numbers are visible. Either option gives every completed assistant turn a footer. Both default to false, so the footer is unchanged unless enabled. /turn-times and /turn-durations (also in the command palette and bindable via session_toggle_turn_time / session_toggle_turn_duration) toggle them at runtime. Like /timestamps, a toggled value persists in kv.json and takes precedence over tui.json, which supplies the default.
Only prompts (/timestamps) and assistant turn footers (/turn-times, turn_timing.time) can show when something happened. Tool calls, thinking blocks, text blocks, errors and compactions never do, so a long run gives no way to see when a step finished or how long a tool call ran. Add a `timestamps` option to tui.json naming the entry types that show a timestamp: "all", "none", a comma-separated list such as "user,tool", or an array. The types are user, assistant, text, reasoning, tool, error and compaction. Tool calls show when they finished and how long they ran; thinking blocks put the time before their existing duration; text blocks and errors get a muted time line; the compaction divider gets the time in its title. All use Locale.todayTimeOrDateFirst, like the turn footer. Unset, nothing changes: /timestamps, /turn-times and turn_timing.time work and persist exactly as before. Set, the list decides every type on each start and overrides turn_timing.time; /timestamps and /turn-times still flip prompt and turn times, until the TUI exits. A kv-wins rule would make the option dead for most existing installs: kv.json usually already holds "timestamps", because the kv store persists its in-memory defaults alongside any other write. The JSON schema description documents every value, since opencode ships no commented tui.jsonc template.
Message footers name the model by its display name only, so the same model served through two providers (openai and a gateway clone, a direct API key and a proxy) reads identically, and nothing on screen says which provider answered a turn. model_label in tui.json picks the label: 'name' (default) keeps the display name; 'id' shows providerID/modelID, e.g. anthropic/claude-sonnet-4-5, in every assistant message footer and in the prompt's model indicator, where it replaces the model and provider names. Variant and duration stay as they are.
Assistant message footers name the model but not the variant it ran with, so a turn on high reasoning effort reads the same as one on the default. The variant is stored on every message and the prompt shows the current one, but nothing shows which one a past turn used. footer_variant in tui.json (default false) adds the message's variant, e.g. high or max, after the model in assistant message footers. Turns without a variant are unchanged. Documented in tui.mdx.
A long session can only be moved through by line, page or the whole transcript. messages_next/messages_previous exist but are unbound, and they skip any prompt within 10 rows of the viewport top, because they compare against a fixed threshold rather than the row they land on. Assistant parts render without an id the scroll position could be matched against. Bind three levels of navigation by default, all overridable in tui.json: - messages_previous / messages_next (ctrl+up / ctrl+down) stop on every user prompt, now through the same picker as the two below. - messages_landmark_previous / messages_landmark_next (ctrl+shift+up / ctrl+shift+down) stop on prompts, the last text part of each turn (its final response), and question, todowrite and task calls. Edits, reads and shell calls are left out because they are as dense as the blocks themselves. - messages_block_previous / messages_block_next (ctrl+alt+shift+up / ctrl+alt+shift+down) stop on every prompt, text part, reasoning part with content, and tool call. Reasoning without content - an encrypted block or an empty "Thinking" placeholder, which GPT models emit on every step - renders as a bare header and is skipped. Text, reasoning and tool boxes now carry their part id so the session route can find them among the scrollbox children, as it already does for user messages by message id. "Previous" and "next" are relative to the row a navigated block lands on, one below the viewport top, so repeated presses walk block by block; past either end the view goes to the top or back to the bottom. messages_first and messages_last also bind ctrl+home and ctrl+end.
Message footers grew one setting per detail, each with its own value shape: turn_timing.time/duration are booleans, timestamps is a type list, footer_variant is a boolean, and the agent, model and total have no setting at all. There was also no way to see a message's ID, which is what logs, the database and the API key everything by. footer in tui.json has one key per detail - agent, model, variant, time, duration, total and the new message_id - and every key takes the same value: true/"all", false/"none", "important", or a list of entry types from the timestamps vocabulary (user, assistant, text, reasoning, tool, error, compaction), which may include "important". "important" selects the landmarks ctrl+shift+up/down stops on, reusing navigationTargets(..., "landmark"); a message-level entry counts when the message or one of its parts is one (isLandmark in navigation.ts). A type a key does not apply to has no effect, which each key's schema description lists. message_id shows the msg_ ID at the end of user and assistant footers as plain text, so it can be selected with the mouse to copy. Time, duration and message_id also give a turn's earlier steps a footer once they finish, as turn_timing did. Every tool call takes time, duration and message_id the same way, whatever renders it - built-in, generic, plugin or MCP tools. A block tool puts them on its own last line and an inline row after its text, or on its own line when the arguments span lines, so a long prompt or command cannot push them out of sight. The footer details are all muted except the agent name, the variant included. Unset keys keep today's behavior: turn_timing, footer_variant and timestamps map onto footer.time, footer.duration and footer.variant (footerSelections in config/index.tsx), and /timestamps, /turn-times and /turn-durations persist as before. A key set in footer decides on every start and its toggle lasts until exit, as timestamps already did. Defaults render the upstream footer unchanged.
Contributor
|
Thanks for this, @Nowaker. The single v1 (the As you mentioned, the right place for it is the |
Contributor
|
The following comment was made by an LLM, it may be inaccurate: |
Nowaker
added a commit
to Nowaker/opencode
that referenced
this pull request
Oct 8, 2026
Item 24: the footer setting, its legacy mapping, the muted variant and the tool-call footer (1ca196f, efc7b3d, 4c6be13), PR anomalyco#53877, and the desktop and m4max installs and tui.json settings. Timeline rows link the turn timing, timestamps, footer variant, model label and block navigation features this changed. AI-Tool: opencode 1.18.34-vt-163-907b3bc518 AI-Model: anthropic/claude-opus-5-5 AI-Variant: high AI-Platform: linux AI-Harness: Vibeterm 23a3dfa AI-Session-ID: ses_ee68aab01ffei41gwUGJ5ESj6W
Nowaker
added a commit
to Nowaker/opencode
that referenced
this pull request
Oct 8, 2026
…int line Item 24 follow-ups (42ce394): the datetime_format setting, a tool call showing its message ID only when the message footer does not, and the footer on a block tool's expand hint line; PR anomalyco#53877 branch and body, the desktop and m4max installs and their tui.json settings. AI-Tool: opencode 1.18.34-vt-163-907b3bc518 AI-Model: anthropic/claude-opus-5-5 AI-Variant: high AI-Platform: linux AI-Harness: Vibeterm fcbe738 AI-Session-ID: ses_ee68aab01ffei41gwUGJ5ESj6W
Nowaker
added a commit
to Nowaker/opencode
that referenced
this pull request
Oct 8, 2026
…er gap Item 24 follow-ups (ea714f8): a running tool call shows its start time and a whole-second stopwatch from one shared clock, finished durations keep tenths up to 11 minutes, and a prompt's footer sits one blank line below its text; PR anomalyco#53877 branch and body, and the desktop and m4max installs through the new v1 database guard gate. AI-Tool: opencode 1.18.34-vt-163-907b3bc518 AI-Model: anthropic/claude-opus-5-5 AI-Variant: high AI-Platform: linux AI-Harness: Vibeterm ab1db14 AI-Session-ID: ses_ee68aab01ffei41gwUGJ5ESj6W
4 of 6 tasks
Nowaker
added a commit
to Nowaker/opencode
that referenced
this pull request
Oct 11, 2026
Item 24: the footer setting, its legacy mapping, the muted variant and the tool-call footer (1ca196f, efc7b3d, 4c6be13), PR anomalyco#53877, and the desktop and m4max installs and tui.json settings. Timeline rows link the turn timing, timestamps, footer variant, model label and block navigation features this changed. AI-Tool: opencode 1.18.34-vt-163-907b3bc518 AI-Model: anthropic/claude-opus-5-5 AI-Variant: high AI-Platform: linux AI-Harness: Vibeterm 23a3dfa AI-Session-ID: ses_ee68aab01ffei41gwUGJ5ESj6W
Nowaker
added a commit
to Nowaker/opencode
that referenced
this pull request
Oct 11, 2026
…int line Item 24 follow-ups (42ce394): the datetime_format setting, a tool call showing its message ID only when the message footer does not, and the footer on a block tool's expand hint line; PR anomalyco#53877 branch and body, the desktop and m4max installs and their tui.json settings. AI-Tool: opencode 1.18.34-vt-163-907b3bc518 AI-Model: anthropic/claude-opus-5-5 AI-Variant: high AI-Platform: linux AI-Harness: Vibeterm fcbe738 AI-Session-ID: ses_ee68aab01ffei41gwUGJ5ESj6W
Nowaker
added a commit
to Nowaker/opencode
that referenced
this pull request
Oct 11, 2026
…er gap Item 24 follow-ups (ea714f8): a running tool call shows its start time and a whole-second stopwatch from one shared clock, finished durations keep tenths up to 11 minutes, and a prompt's footer sits one blank line below its text; PR anomalyco#53877 branch and body, and the desktop and m4max installs through the new v1 database guard gate. AI-Tool: opencode 1.18.34-vt-163-907b3bc518 AI-Model: anthropic/claude-opus-5-5 AI-Variant: high AI-Platform: linux AI-Harness: Vibeterm ab1db14 AI-Session-ID: ses_ee68aab01ffei41gwUGJ5ESj6W
Nowaker
added a commit
to Nowaker/opencode
that referenced
this pull request
Oct 12, 2026
Item 24 follow-up (c642043): today checks read a shared local-day signal, so footers and timestamps already on screen switch to the date and time at 00:00 from one timer; PR anomalyco#53877 branch and body, the restacked tui-tool-collapse branch, and the desktop and m4max installs. AI-Tool: opencode 1.18.34-vt-163-907b3bc518 AI-Model: anthropic/claude-opus-5-5 AI-Variant: high AI-Platform: linux AI-Harness: Vibeterm ab1db14 AI-Session-ID: ses_ee68aab01ffei41gwUGJ5ESj6W
4 of 6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Note: I'm aware v1 is now the maintenance branch and new features go to v2 only. This PR is here for others to use, and I'll submit the v2 version once I've migrated my whole plugin system to it.
Issue for this PR
Related: #42498, #38666, #50891 (finished tool calls only; no live timer while a call runs).
Stacked on #53195 (turn timing), #53654 (
timestamps), #53639 (model_label), #53848 (footer_variant) and #53333 (landmark navigation), because it unifies their settings. Their commits are included; the change in this PR is the last commit,feat(tui): add footer to choose every message footer detail the same way.Type of change
What does this PR do?
Message footers show a handful of details - agent, model, variant, finish time, duration, total - and each one is switched on its own way: some are booleans,
timestampsis a list of entry types, and some can't be switched at all. Tool calls only get a time when the right setting is set, and on a plugin or MCP tool with a long multi-line argument the time ends up at the end of the last line, easy to miss. There is also no way to see a message's ID, which is what logs, the database and the API use, and no way to change how times and dates are written: they always come out in the runtime's locale, which Bun resolves to en-US (2:20 PM,10/7/2026) whateverLANGsays.This adds one
footerobject totui.jsonwith one key per detail:agent,model,variant,time,duration,totaland the newmessage_id. Every key takes the same value:"all"/true, or"none"/false;"important"- only on the entries ctrl+shift+up/down stops on (prompts, each turn's final response, question/todo/subagent calls), reusing that navigation's landmark list;timestampsvocabulary (user,assistant,text,reasoning,tool,error,compaction), which may include"important".{ "footer": { "variant": "all", "time": "important,tool", "duration": "assistant,tool", "message_id": ["user", "assistant", "tool"] } }toolcovers every tool call, whatever renders it: built-in, generic, plugin and MCP tools. A block tool shows its footer on its own last line, or on itsClick to expandhint line when it has one; an inline row shows it after its text, or on its own line when the arguments span lines.16:25:29 · 37s,2m 5s), all running calls sharing one 1s clock that stops when none is running. Once finished it shows the end time and the duration, with tenths of a second up to 11 minutes (4.8s,2m 5.3s, then11m 0s).message_id: "tool", or"important"leaving a plain step's footer out).message_idis plain text, so it can be selected with the mouse and copied.totalonly exists on a turn's final message, for example).A separate
datetime_formatsets the date and time patterns, in Day.js tokens, for every time the TUI writes (footers, entry timestamps, the compaction divider, the timeline and stash dialogs). Entries from today still show only the time. Each part accepts only its own tokens, soHH:MM:SSis rejected instead of printing the month as the minute:{ "datetime_format": { "date": "YYYY-MM-DD", "time": "HH:mm:ss" } }gives
14:20:07today and2026-10-07 14:20:07for older entries. At local midnight, times already on screen switch to the date-and-time form by themselves; one shared timer drives this, firing after midnight or within the hour, so a suspend or clock change is caught too.Nothing changes unless
footerordatetime_formatis set. The older keys keep working and map onto it:turn_timing.time/duration,footer_variantandtimestamps./timestamps,/turn-timesand/turn-durationsstill toggle prompt times, turn times and turn durations; for a key set infooterthe toggle lasts until exit, as it already did fortimestamps.How did you verify your code works?
bun typecheckandbun testinpackages/tui, with new tests for value parsing, the legacy mapping,"important"resolution, the message-ID-once rule, the shared ticker starting and stopping, the stopwatch and decimal rules, the prompt footer gap, the tool footer formatter, the multi-line row,datetime_formattokens and validation, and a fake clock crossing midnight flipping a rendered footer with a single shared timer.vtpsthat takes a multi-line prompt and returns enough output to collapse. With nofooterthe transcript matchesdev; the legacy keys render as before. Clicking the hint still expands and collapses the block.Screenshots / recordings
footerset to"all"for every key,datetime_formatYYYY-MM-DD/HH:mm:ss, generic tool output shown:Checklist
This PR is AI generated, but under direct supervision and on request of @Nowaker.