Customizable status line

Open 💬 41 comments Opened Apr 14, 2026 by pkondaurov
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

Feature Request

Problem

Claude Code has a built-in customizable status line feature that allows users to display useful real-time information at the bottom of the terminal UI — token usage, model name, rate limits, context window, git branch, etc.

This is configured via a simple shell script hook in settings:

{
  "statusLine": {
    "type": "command",
    "command": "/bin/bash ~/.claude/statusline.sh",
    "padding": 0
  }
}

The script receives JSON context on stdin and returns formatted text. This is incredibly useful for power users who want to monitor their session at a glance.

Codex CLI currently has no equivalent mechanism. There's no way to display custom information in the TUI — no status line, no hooks, no plugin system for UI customization.

Proposed Solution

Add a statusLine (or similar) configuration option to ~/.codex/config.toml that allows running an external command and rendering its output in the Codex TUI (e.g., at the bottom of the screen).

Something like:

[status_line]
command = "/bin/bash ~/.codex/statusline.sh"
refresh_interval_secs = 10

The command would receive session context (model, token count, etc.) as JSON on stdin and return a single line of text (with ANSI colors) on stdout.

Use Cases

  • Display current model and token/context usage
  • Show API rate limit status and reset times
  • Display git branch and repo info
  • Show project-specific metadata
  • Integration with external monitoring tools

Why This Matters

For users who switch between Claude Code and Codex, the lack of a status line in Codex is a noticeable gap. The status line is a low-cost, high-value feature that significantly improves the interactive experience.

View original on GitHub ↗

41 Comments

github-actions[bot] contributor · 4 months ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #16921
  • #16393

Powered by Codex Action

etraut-openai contributor · 4 months ago

Have you tried the /statusline command? It's a little less flexible than an arbitrary script, but it's much easier to configure. Does this meet your needs?

joshka · 4 months ago

I'd like to be able to see my jj-vcs status (change id etc.) in the status line.
It's likely not a small task to invest in making jj a core part of the product, but allowing a hook like this seems like a reasonable compromise https://github.com/openai/codex/issues/16921 seems like they have a good solution to this with a proposed PR ready to review

dlwss · 4 months ago
Have you tried the /statusline command? It's a little less flexible than an arbitrary script, but it's much easier to configure. Does this meet your needs?

The current exposed features have significantly enhanced the functionality, and they can meet the needs of most users in various scenarios. However, I still hope to be able to add an extension point similar to the Statusline of CC CLI. It can store some user-defined data. If it can be made available, I would be very grateful.

jage9 · 4 months ago

Found this while researching this exact idea.
/statusline is actually a decent compromise, though I would still like to have control over the wording and order for conciseness.
For example, I have my Claude one at
5H: 96% | 7D: 100% | context: 89% | Sonnet 4.6
Since I use a screen reader, being able to set the order is important to me.

YitzhakMizrahi · 4 months ago

The built-in /statusline command is useful, but it does not fully cover the use case of a dynamically refreshed status provider. The gap I am running into is less "show one more built-in field" and more "let the user define what the statusline and/or terminal title should say while a session is running."

Useful shape:

  • A configurable command or template that receives current session context, such as model, cwd, repo/branch, approval mode, sandbox mode, turn state, and token/context usage when available.
  • Automatic refresh on a timer and on relevant session events, rather than requiring manual updates.
  • Separate control for the visible statusline/footer and the terminal/window title.
  • User-defined ordering, visibility, and formatting, which helps both compact multiplexer panes and accessibility workflows.
  • Safe failure behavior: if the command times out or exits nonzero, keep the previous value or render nothing, but do not block the TUI.

This would make /statusline a good default for most users while still giving power users a narrow extension point for project-specific or workflow-specific context.

RoggeOhta · 4 months ago

Adding another +1 for command-driven customization specifically, not just selecting built-in /statusline fields.

The current /statusline is useful, but the gap vs Claude Code is the extension point: let users run a command/script, pass Codex session context as JSON on stdin, and render stdout with safe timeout/failure behavior.

Use cases:

  • Show project-specific info that Codex will never know as built-in fields, e.g. jj change id, k8s context, CI/deploy status, ticket id, custom quota/spend.
  • Preserve a compact house style across tmux/zellij panes.
  • Support accessibility by controlling exact wording/order rather than choosing from fixed labels.

A built-in /statusline default and an opt-in command provider could coexist: default remains simple, power users get a narrow, predictable extension hook.

akamalov · 4 months ago

+1

SakaZulu · 4 months ago

Thanks, I noticed #17827 is very closely related.

I am fine with this issue being treated as a duplicate if that helps tracking. The main point I wanted to emphasize is the same as the later comments in #17827: the built-in /statusline picker is useful, but the missing piece is a command-driven extension point.

For my use case, the important part is not just adding more built-in fields. It is allowing a user-provided command to receive Codex session context as JSON on stdin and render stdout back into the TUI, preserving ANSI colors and custom formatting, with timeout/failure safeguards.

That would let the built-in /statusline remain the simple default while enabling advanced users and community tools to build richer status lines.

lapcchan · 3 months ago

/statusline customize is ready. it's just i can't change the color of the statusline...

akamalov · 3 months ago

when will it get merged to main?

kanine · 3 months ago

<img width="437" height="26" alt="Image" src="https://github.com/user-attachments/assets/70173c24-3343-40e7-9e75-d85a2295a6bc" />

I just finished customizing my statusline in another app and stumbled upon this request. This is reminiscent of the old days of internet quotas. I used to track with over/under indicators like I've done here.

Adding a similar scripting ability to Codex is a +1 from me.

CondorCommodore · 3 months ago

Adding another concrete use case for command-backed status-line support:

I need to show local coordination/watch health in the Codex TUI footer, e.g.

watchers:live
watchers:stale
watchers:dead

The status comes from a local script that checks a daemon PID, output freshness, and pending inbox events. Today I can approximate this with UserPromptSubmit hooks that emit systemMessage, but that is not equivalent: it only appears at turn boundaries and only as transient transcript output. The operator still has no persistent footer signal that the watcher is healthy while working.

The current [tui].status_line = [...] built-in picker is useful for Codex-owned state, but this is external workflow state. A command-backed status-line item or banner would solve it cleanly:

[tui]
status_line = [
  { type = "command", command = "~/path/to/statusline-watchers.sh", timeout_ms = 200 },
  "model-with-reasoning",
  "current-dir",
  "context-usage",
  "weekly-limit"
]

Key requirements from this use case:

  • runs on startup and periodically / turn-start
  • bounded timeout
  • command stdout renders as one compact status segment
  • failure should degrade to an omitted or error segment, not break the TUI
  • no need for secrets or model context; cwd/session id are enough

This would let Codex support project-local operational telemetry without expanding the built-in status enum for every workflow-specific field.

stormzhang · 2 months ago

+1. I maintain token-tracker, which renders a rich quota / context / cost statusline on Claude Code via its official StatusLine API — but on Codex I'm stuck with the default style, since there's no custom hook. Same data locally, no way to render it.

!Claude Code statusline

Copying Claude Code's design would close the gap — a command that gets session JSON on stdin and prints a styled string to stdout:

[tui.status_line]
type = "command"
command = "~/.codex/statusline.sh"

Keep the enum items as default, treat command as opt-in. Happy to test a branch.

aqua5230 · 2 months ago

+1 — this is the single biggest gap for me when switching between Claude Code and Codex.

A concrete reference that this is both feasible and high-value: I maintain usage, a macOS menu-bar/TUI tool that pins Claude Code + Codex quota to the screen (all from local files — no API calls).

On the Claude Code side it ships exactly the statusLine command hook proposed here, and renders something like:

usage(main) | 5h ▕███████▏ 99% (9min left) | 7d ▕█▏ 11% (6d13h left)

…with unicode meters, per-threshold colors, and a derived "time-until-reset" — all from a single script that reads local files off stdin.

On the Codex side we're limited to the fixed tui.status_line enum, so the best we can offer users is plain text:

5h 4% left · weekly 33% left · Context 68% left · gpt-5.5 medium

Same underlying data, but we can't draw the meters / colors / countdowns because there's no command-backed hook to render arbitrary output.

The proposed [status_line] command = "..." shape (JSON context on stdin → one ANSI line on stdout) is exactly right — it mirrors Claude Code 1:1, so existing scripts and tools port over with near-zero friction. If this lands, we'd ship Codex support for it the same week. 🙏

vittoriohalfon · 2 months ago

I've prototyped a minimal version of this and would be glad to contribute it if the team is open to an invited PR (I see contributions are invitation-only — happy to follow whatever process you prefer).

Design — one self-contained [tui] key, with no change to the existing status_line item list:

[tui]
status_line_command = { command = ["my-script"], timeout_sec = 5, interval_sec = 10, position = "end" }

The command is fed session context as JSON on stdin (model, reasoning_effort, cwd, git_branch, session_id, approval_mode, sandbox_mode, context_used_pct/context_remaining_pct, context_window, codex_version) and its first stdout line is rendered as a status-line segment — mirroring Claude Code's statusLine.command. Execution is async / non-blocking: it reuses the existing hooks command-runner pattern (configurable timeout, kill_on_drop), re-runs on an interval, and the output is sanitized to a single escape-free line so it can't corrupt the TUI.

It's implemented against main, kept intentionally small (no /statusline picker changes), with config-deserialize + TUI render tests passing and cargo fmt / clippy clean.

A couple of things I'd want the team's steer on before any PR:

  • Cross-surface consistency — should the same key eventually be honored by the IDE / web surfaces, or is this CLI-only for now?
  • Execution model — argv-direct (what I have) vs a shell string, to match whatever convention you'd prefer.

Happy to share the branch or adjust the design to fit your roadmap. Thanks!

Necmttn · 2 months ago

Command-backed status lines work if the contract is small and bounded. Send JSON with session id, model, cwd, git branch, approval/sandbox mode, context usage, quota snapshot, and version. Enforce timeout, refresh interval, max output width, and stale-output behavior. That lets local quota/watch tools render state without giving the command transcript access or blocking the TUI.

---

_Generated with ax._

AlanineX · 2 months ago

For anyone who mainly wants local host telemetry in the meantime, I published a small tmux-based workaround: https://github.com/AlanineX/codex-host-status

It does not replace the native feature request here. It wraps interactive codex sessions, leaves subcommands like codex exec / codex doctor untouched, and renders a compact status bar like:

🐍 base ⚙ CPU 4% 41C 🎮 GPU 2% 43C 0.6G 💾 RAM 10.1/47G 🕒 14:29

This covers my local CPU/GPU/RAM visibility use case while waiting for a real command-backed tui.status_line hook in Codex.

stormzhang · 2 months ago

+1 on this. I shipped a workaround for the same use case as an open-source CLI (token-tracker) and want to share what users actually need vs. what the built-in /statusline can express today.

What we ended up doing: since Codex has no command-backed statusline hook, we inject a two-line "faux statusline" via the Stop hook, returning systemMessage after every turn. It renders with 24-bit truecolor, shows project + branch + diff + session tokens + cost + 5h/7d quota + context %, and follows the active theme. (Verified: does not enter the model context.)

!Codex faux statusline screenshot

Why /statusline wasn't enough:

  • Fixed enum items don't compose into the multi-line layout users want (progress bars + diff stats + cost + reset countdowns).
  • No way to call external scripts that already track project context / usage.
  • No per-item theming/coloring control.

What would unblock the whole class of tools: exactly what Claude Code does — accept a command/script-based statusline (stdin JSON in, formatted text out). Today we're stuck with a hidden Stop-hook workaround that renders in the response area (not the bottom bar), depends on Stop-hook + systemMessage being stable, and is hard for new users to discover.

Happy to share implementation details if useful. Thanks for considering.

string-theorist · 1 month ago

+1. I run a workflow/governance tool that's meant to work across different agents, but it leans heavily on Claude Code's statusLine. We keep a little state file (active task, pipeline stage, drift, context left) that the hooks update, and the statusline just renders it. Codex already has the hooks now, there's just nowhere to show it natively. Would love to port it over: an opt-in { type = "command", command, timeout_ms } that gets the session JSON on stdin and renders stdout, with a timeout.

Thanks for the great work on this!

pzarzycki · 1 month ago

Related to this, here's a small tool. It is not a live status line, but it helps inspect local Codex/Claude session data so token usage and session details are less opaque, without API keys or sending logs anywhere.

Open source:
https://github.com/pzarzycki/token-companion

If you like it - leave a star; submit an issue or request, or even a PR!

lindestad · 1 month ago

Just want to add in that this would be extremely useful for improving the way the current statusline renders items when displaying multiple items. Codex cli is easiest to read when not set to the entire screen width, but then items overflow:

gpt-5.5 xhigh · ~/dev/project · Context 46% used · 5h 80% left · weekly … Vim: Normal

Being able to style these, and/or have some of them only appear at desired thresholds (like weekly/5h only appearing below a certain remaining level) enhances the statusline massively, it could instead render as

5.5 xhigh · ~/dev/project · Ctx 46% · 5h 80% · week 72% · Vim: Normal

This is the same statusline information, but it now renders all the information (weekly is cut off originally).

Allowing the user to do this would be fantastic.

ducky-duke · 1 month ago

+1

mark-undoio · 1 month ago

We ship a tool that integrates with coding agents and the lack of a flexible status line is quite painful to our customers - it means they've got no way to display progress information from within our stack when the agent is driving our tool. It makes the workflow more opaque for them as they can't tell what the agent is doing or why.

Ideally we'd be able to supply a default script for status line behaviour that less advanced users can just configure, with more advanced users being able to script whatever they want from our feedback and other sources.

Edit to add: Alternatively, the ability to supply a JSON blob for formatting / filtering within the agent's status line config would also work well.

jleme · 1 month ago

The current status line configuration is limited to built-in fields and does not support customer-specific workflow needs, such as command-backed content, semantic colors, or conditional indicators. Please consider supporting an extensible status line API.

Nutcasey · 1 month ago

I'd like to see this too.

shenxingy · 1 month ago

Adding a concrete, shipping use case for a command-backed status line (distinct from picking more built-in fields).

We ship $codex-usage as a Codex-native workflow. It reads rate-limit snapshots through the authenticated codex app-server protocol (it never opens auth.json) and renders a compact pace indicator against a 95%-utilization target. Its default output is already exactly one status line:

Clade(main) 🐣 -12% (6d)

i.e. <project>(<branch>) <pace-glyph> <±pace-vs-target>% (<resets-in>), and it also emits a machine-readable payload a hook could consume directly:

$ codex-usage --json
[
  {
    "limit_id": "codex", "name": "Codex", "window": "week",
    "used_percent": 2, "remaining_percent": 98,
    "resets_in": "6d", "pace_delta": -12.5, "projected_percent": 13.1
  }
]

The one thing we can't do is surface this persistently in the TUI. [tui].status_line is a fixed enum of built-in item ids, so today the pace line only lives in an on-demand invocation or a transient session-start message — it can't stay pinned in the footer the way Claude Code's statusLine.command keeps a custom renderer live.

The missing piece is exactly the extension point in this issue: Codex pipes session/rate-limit JSON to a user command on stdin and renders its stdout (first line, ANSI-aware) in the footer, with a timeout + fail-open so a slow or failing command never blocks the TUI. Additive to the existing field picker, roughly:

[tui]
status_line = ["current-dir", "git-branch"]   # built-in fields still work

[tui.status_line_command]                      # new: command-backed segment
command = ["codex-usage"]                       # already prints one status line
refresh_interval_secs = 30
timeout_ms = 800                               # on timeout / non-zero exit: keep last good line

PR #10170 already demonstrated a working implementation; the status surface has since been refactored into tui/src/bottom_pane/, so it would need a fresh pass on the current architecture rather than a straight rebase. Happy to help build and test it against a real renderer ($codex-usage) if there's maintainer appetite.

shenxingy · 1 month ago

I put together a working implementation on today's bottom_pane architecture: compare diff.

It adds a custom status-line item backed by [tui].status_line_command (argv) — Codex runs it on a timer, pipes a small JSON session snapshot ({cwd, git_branch, model}) on stdin, and renders the first stdout line, with a 1.5s timeout + kill-on-drop and fail-open (keeps the last good value), mirroring the async workspace-headline item. A snapshot diff re-runs it immediately on a branch/dir switch so the footer isn't stuck on stale data. Rebases cleanly on main; clippy/fmt clean; the command-runner unit tests plus the full status_line tui suite pass.

This repo limits opening PRs to collaborators, so I can't open one directly — happy to if a maintainer enables it, or the branch is here to cherry-pick: shenxingy:feat/status-line-command.

pavelbe · 1 month ago

+1. Use case: side-by-side multi-terminal agent workflows (Claude Code + Codex CLI in split panes). We render cross-session mailbox/peer badges in Claude Code via its statusLine command hook, but Codex's [tui].status_line only accepts built-in item identifiers — so the Codex pane can't show a symmetric indicator. A custom command item (or a single script-fed text item) would cover this.

knk0715 · 1 month ago

I hit this limitation on Codex CLI 0.145.0 while trying to reproduce a compact Claude Code-style footer.

The current implementation makes even small presentation changes impossible:

  • tui.status_line accepts only the built-in StatusLineItem IDs.
  • Literal text such as " | " is accepted by the TOML/schema layer but later ignored by the TUI as an invalid item.
  • The separator is hard-coded to " · ".
  • There is no supported way to add one blank/padding row above or below the status line.
  • Session token counters are available, but account-level cumulative/allocated token usage is not available as a footer field; it requires opening /usage.
  • --strict-config does not catch invalid status-line IDs, so the configuration can validate successfully and still be partially ignored at runtime.

Please consider supporting:

  1. Literal/static segments or a configurable separator.
  2. A command-backed custom status line compatible with Claude Code-style JSON input/output.
  3. Optional footer padding or an additional persistent line.
  4. Account usage fields where the backend exposes them.
  5. Strict validation of status-line item IDs.

This is a small customization surface, but the current fixed renderer creates a surprisingly large usability gap for users moving between Claude Code and Codex.

L-svg-png · 1 month ago

I have a working implementation of this and would like to offer it — happy to adjust the design before opening a PR, and mindful that external PRs here are by invitation, so posting the approach first.

Shape: one new config table plus one new item id, everything else reuses existing machinery:

[tui]
status_line = ["model-with-reasoning", "custom", "git-branch"]  # optional; "custom" is auto-appended to defaults if status_line is unset

[tui.status_line_command]
command = "~/.codex/statusline.sh"   # JSON on stdin, first stdout line rendered
refresh_interval_ms = 10000          # default 10000, floor 1000; output cached between runs
timeout_ms = 1000                    # default 1000; child killed at deadline

Key design points:

  • The stdin JSON is deliberately field-compatible with Claude Code's statusLine contract (model.display_name, workspace.current_dir, context_window.*, rate_limits.*, snake_case, same omit/null rules, COLUMNS/LINES in env), so the existing ecosystem of third-party status-line scripts runs on both tools unmodified. Codex extensions: permission_mode, git_branch.
  • Execution reuses the hooks engine's command runner (extracted into a shared helper, hooks behavior byte-identical), and the TUI side copies the async fetch-and-cache pattern the workspace-headline/git-summary segments already use — no UI-thread blocking, no timers.
  • Robustness: keep-last-good on failure, empty stdout = hide, circuit breaker after 5 consecutive failures, output sanitized (first line, ANSI/control/bidi stripped, grapheme-capped) before it touches the renderer.
  • Security: same posture as notify — the key is stripped from project-local .codex/ config layers, so a cloned repo can never register a command.
  • Purely additive; would close this issue and consolidate #20043 / #20140 / #20244 (related: #16921).

Branch with the full implementation and test battery: feat/status-line-command. If maintainers are open to it I'd appreciate design feedback — especially on the config key name, the auto-append rule, and whether the Claude-Code-compatible stdin shape is acceptable — and can open the PR whenever invited.

L-svg-png · 1 month ago

Credit where it's due — @shenxingy proposed this same shape ([tui.status_line_command] + a custom item, mirroring the workspace-headline async pattern) a week before I posted, and even landed on the same branch name. I found the convergence after posting; their comment deserves the priority.

Where mine may still add something on top of theirs: the stdin payload is the full Claude Code statusLine schema rather than a minimal snapshot (so existing third-party scripts run unmodified), plus a security posture that strips the key from project-local .codex/ layers so a cloned repo can't register a command, output sanitization (ANSI/C0/C1/bidi + length caps), a circuit breaker after repeated failures, and the hooks command-runner extracted into a shared helper — which also fixes a real bug where the stdin write sat outside its own timeout.

Happy for maintainers to take whichever branch is more useful, or for the two to be merged — @shenxingy, glad to combine if you're up for it.

shenxingy · 1 month ago

Thanks for the thoughtful follow-up and for the credit — I’m happy to collaborate.

Your Claude Code-compatible payload and the additional security/sanitization work are valuable additions. My branch was intentionally kept minimal, so it may still be useful as a smaller reference if the maintainers prefer a narrower change.

Since external PRs are invitation-only and the maintainers haven’t selected a design yet, I suggest we wait for their guidance before merging the branches. If a PR is invited, I’d be glad to help review and test the combined implementation against Clade’s codex-usage renderer, and to contribute whichever parts of my branch are useful.

unger1984 · 1 month ago

This feature request is clearly in demand: the thread already contains many practical use cases, and the two recent implementations show that a command-backed status line can be added without changing the TUI core model.

After comparing shenxingy:feat/status-line-command and L-svg-png:feat/status-line-command, I think L-svg-png is the stronger foundation. The nested configuration, preventing command execution from project-local config, output sanitization and caps, timeouts, and failure handling address important security and reliability concerns.

That said, the current scope, around 45 files including a refactor of the shared command execution mechanism, may make review harder. For a first version, it may be worth keeping only the necessary functionality and splitting the shared refactor into a separate PR. From shenxingy's implementation, I would keep argv-based command execution: it is more predictable and safer than implicitly running a shell string.

It would also be useful to version the script input payload. Claude Code compatibility should be defined as a supported subset, rather than an open-ended commitment to fully mirror another project's contract. Could maintainers clarify the minimum set of requirements they would accept for a v1? That would help the authors converge on one implementation and get it merged sooner.

@etraut-openai, since you previously suggested /statusline as the supported path, could you clarify whether the team would consider a command-backed custom segment for a minimal v1, and which constraints or requirements would be mandatory?

L-svg-png · 1 month ago

Thanks @unger1984 for the detailed comparison, and agreed with @shenxingy on waiting for maintainer guidance before converging branches.

All three suggestions sound right to me, and I've checked each against my branch so this isn't hand-waving:

  • Scope / split: happy to split for reviewability. The shared command-runner extraction stands alone cleanly (~550 lines; it also fixes an existing hook-runner bug where the stdin write sat outside its own timeout), with the config+security layer and the TUI item as separate follow-ups. I'd move the stdin schema into the TUI piece so the runner refactor stays pure.
  • argv: agreed this is the better execution model — glad to adopt @shenxingy's argv semantics. There's an exact precedent already in the codebase (notify's untagged bool-or-array config shape): command can accept a TOML array (exec'd directly, no shell) alongside the string form for compatibility with existing Claude Code scripts. The argv path inherits all the existing hardening unchanged (single timeout envelope, kill-on-drop, capped concurrent pipe reads) — roughly a 150–200 line delta.
  • Versioned payload / bounded compatibility: agreed. Concretely: a payload_version: 1 integer field (the existing version field carries the CLI version, matching Claude Code's), bumped only on breaking changes — plus Claude Code compatibility defined as a documented, guaranteed subset of fields rather than an open-ended commitment to mirror another project's contract. Scripts must tolerate absent fields; Codex-specific additions stay documented extensions.

Whatever constraints the maintainers set for a v1, between the two branches the pieces are ready.

adrisinan · 28 days ago

+1. Another concrete use case the built-in item list can't cover: when was this conversation last active.

I keep several agent TUI sessions open across days (Codex CLI, Claude Code, others, in separate terminal tabs). Coming back the next day, I can't tell which tab holds which conversation or how stale each one is. In Claude Code the command-backed status line solves it in three lines of shell — the script stats the transcript file's mtime and renders the last-response time (e.g. ⏱ 31/07/2026 12:55) in the footer, formatted for my locale.

In Codex this is currently impossible: neither the status_line nor the terminal_title item sets include any clock/timestamp/last-activity item, unknown identifiers are warned about rather than rendered literally, and hook-based workarounds (writing the terminal title from a Stop hook) get repainted over by the TUI's own title management.

A command-backed status line as proposed here would cover this and every similar niche without OpenAI having to anticipate them. Failing that, even a built-in last-activity item (timestamp of the last turn, locale-aware) would go a long way for multi-session workflows.

Chengyf2004 · 25 days ago

My use case is related to this issue, but I need more than a user-customizable status line.

I would like the agent itself to update a persistent semantic task status in the TUI. For example:

Atlas (repository understanding) · Investigating · 2/5
Current: Comparing CLI parsing logic with the README

The status should not be emitted as normal assistant text, because it is quickly pushed out of view by tool output. Instead, the agent should call a structured tool such as set_task_status, which emits a dedicated event consumed by the TUI.

Suggested fields:

  • phase: investigating, implementing, testing, waiting_for_approval, blocked, done
  • message: current activity
  • optional progress: completed / total

The TUI could also derive fallback status from plan updates, active commands, approval requests, and turn completion events.

Related: #21327, #22099.

Would you prefer this to be tracked as part of this status-line issue, or as a separate issue focused on agent-controlled task status?

vmindru · 23 days ago

Concrete production use case for this extension:

My session-start hook obtains the active Vornik RAG context:

Vornik: popron-devops:.../devops/slava

Today it can only print this as transcript text; it cannot add it to the persistent Codex footer. That makes it easy to lose the active AI-ops project/scope when several Codex sessions are open.

Suggested contract:

  • A custom status-line item placed alongside built-ins in [tui].status_line.
  • It invokes one explicitly configured, user-level command with a small JSON session payload on stdin.
  • Async refresh with a tight timeout, cached last-good value, and fail-silent fallback.
  • One sanitized single-line output; the provider must not replace or obscure Codex-owned operational/safety fields.
  • Disabled by default; do not allow project-local configuration to register the command.

This would support Vornik scope, CI/build state, ticket identifiers, and similar local workflow metadata without adding each integration as a built-in item.

joshlewis · 18 days ago

I would also say it's not just about use cases. It's about preferences. In other words, I don't want the string "Context 42% used", I want "Ctx: 42%". I don't have infinite space in my status line. I need to squeeze more information in there. Same use case, different preference. Let people use this in a way that suits them, not just in the ways the top-down approach allows.

ecgang · 17 days ago

Two notes on the command-backed direction — one a defect worth fixing before it ships, one a triage observation.

The project-local protection is key-specific, and that's a trap

Every prototype here correctly refuses to let a project-local .codex/ layer register a command — otherwise cloning a repo would run its author's shell command on your machine. In the current shape that's enforced by stripping one named key, tui.status_line_command, from project layers.

That works today and breaks quietly later. The protection isn't attached to the dangerous property, it's attached to a spelling. Any future key that spawns a process — a second provider, a segment-scoped command, a per-item override, an env-var hook — is unprotected until someone remembers to add it to the strip list. Nothing fails loudly when they don't. The config parses, the feature works, and a cloned repo gets code execution.

The fix is small if it happens now and awkward if it happens after the fact: make "spawns a process" a property the config schema carries, and drive the project-layer strip off that property rather than a list of names. Same behavior today, but the protection is inherited by construction instead of re-earned per key. Adding a command-backed key then can't silently reopen the hole, because there's nothing to forget.

I'd suggest whichever branch lands first carries this, since it costs little now and each additional command-backed surface makes it more expensive.

Two comments in this thread are asking for a different surface

Not a criticism of either — the footer is the only extension point being discussed, so it's where the requests land. But they describe something the footer can't do:

  • @mark-undoio (2026-07-09) — an integrated tool with "no way to display progress information from within our stack when the agent is driving our tool... they can't tell what the agent is doing or why." That's opacity during a turn.
  • @Chengyf2004 (2026-08-03) — opens with "I need more than a user-customizable status line," and wants the agent to update semantic progress (Investigating · 2/5) as work happens.

Both want content that appears while the agent is working and goes away when it stops, tied to the turn rather than the session. The footer is the wrong lifetime for that: it's persistent and interval-driven, so expressing "what's happening right now, and how long it's been" means either burning permanent footer space on something transient, or polling for state the footer payload has no reason to carry.

That surface is StatusIndicatorWidget, and it's tracked separately in #35480 — including the part that doesn't exist here, which is precedence policy: what custom content may render during a turn, and what it must never mask (approvals, permission review, retries, errors, MCP startup, subagent waits). Pointing it out so the footer design doesn't get stretched to cover a lifetime it doesn't fit, and so those use cases land somewhere they can actually be served.

The sanitization point above applies to both surfaces, which is why it's here rather than there.

rianjs · 17 days ago
I would also say it's not just about use cases. It's about preferences. In other words, I don't want the string "Context 42% used", I want "Ctx: 42%". I don't have infinite space in my status line. I need to squeeze more information in there. Same use case, different preference. Let people use this in a way that suits them, not just in the ways the top-down approach allows.

Couldn't agree more. Having control over the density is great:

claude-fable-5 high | ctx:69/1000K (7%) | 5h:17% (9:00am) | ↻ 5 ~/d/y/facade | session-name | 66463a43-1aee-4837-9b47-847b8b91fb2b

↻ 5 is the number of compactions in the session.